Merge branch 'master' into argv-cleanup-26

This commit is contained in:
Mike McQuaid 2020-05-23 13:44:42 +01:00 committed by GitHub
commit e5d15c8b19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
348 changed files with 1972 additions and 912 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
Library/Homebrew/vendor/portable-ruby
Library/Taps

56
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,56 @@
name: Docker
on:
pull_request:
paths:
- .github/workflows/docker.yml
- Dockerfile
release:
types:
- published
jobs:
ubuntu:
runs-on: ubuntu-latest
strategy:
matrix:
version: ["16.04", "18.04", "20.04"]
steps:
- name: Checkout
uses: actions/checkout@master
with:
fetch-depth: 0
persist-credentials: false
- name: Fetch origin/master from Git
run: git fetch origin master
- name: Build Docker image
run: docker build -t brew --build-arg=version=${{matrix.version}} .
- name: Run brew test-bot
run: docker run --rm brew brew test-bot
- name: Deploy the tagged Docker image to GitHub
if: startsWith(github.ref, 'refs/tags/')
run: |
brew_version=${GITHUB_REF:10}
echo "::set-env name=brew_version::$brew_version"
docker login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}}
docker tag brew "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:$brew_version"
docker push "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:$brew_version"
docker tag brew "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:latest"
docker push "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:latest"
- name: Deploy the tagged Docker image to Docker Hub
if: startsWith(github.ref, 'refs/tags/')
run: |
docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}}
docker tag brew "homebrew/ubuntu${{matrix.version}}:$brew_version"
docker push "homebrew/ubuntu${{matrix.version}}:$brew_version"
docker tag brew "homebrew/ubuntu${{matrix.version}}:latest"
docker push "homebrew/ubuntu${{matrix.version}}:latest"
- name: Deploy the homebrew/brew Docker image to GitHub and Docker Hub
if: startsWith(github.ref, 'refs/tags/') && matrix.version == '20.04'
run: |
docker tag brew "docker.pkg.github.com/homebrew/brew/brew:$brew_version"
docker push "docker.pkg.github.com/homebrew/brew/brew:$brew_version"
docker tag brew "docker.pkg.github.com/homebrew/brew/brew:latest"
docker push "docker.pkg.github.com/homebrew/brew/brew:latest"
docker tag brew "homebrew/brew:$brew_version"
docker push "homebrew/brew:$brew_version"
docker tag brew "homebrew/brew:latest"
docker push "homebrew/brew:latest"

View File

@ -3,9 +3,9 @@ on:
push: push:
branches: master branches: master
pull_request: [] pull_request: []
release: env:
types: HOMEBREW_GITHUB_ACTIONS: 1
- published HOMEBREW_NO_AUTO_UPDATE: 1
jobs: jobs:
tests: tests:
if: github.repository == 'Homebrew/brew' if: github.repository == 'Homebrew/brew'
@ -18,7 +18,8 @@ jobs:
id: set-up-homebrew id: set-up-homebrew
run: | run: |
if which brew &>/dev/null; then if which brew &>/dev/null; then
HOMEBREW_REPOSITORY="$(brew --repo)" HOMEBREW_PREFIX="$(brew --prefix)"
HOMEBREW_REPOSITORY="$HOMEBREW_PREFIX/Homebrew"
else else
HOMEBREW_PREFIX=/home/linuxbrew/.linuxbrew HOMEBREW_PREFIX=/home/linuxbrew/.linuxbrew
HOMEBREW_REPOSITORY="$HOMEBREW_PREFIX/Homebrew" HOMEBREW_REPOSITORY="$HOMEBREW_PREFIX/Homebrew"
@ -30,11 +31,11 @@ jobs:
sudo mkdir -p bin etc include lib opt sbin share var/homebrew/linked Cellar sudo mkdir -p bin etc include lib opt sbin share var/homebrew/linked Cellar
sudo ln -sf ../Homebrew/bin/brew "$HOMEBREW_PREFIX/bin/" sudo ln -sf ../Homebrew/bin/brew "$HOMEBREW_PREFIX/bin/"
cd - cd -
export PATH="$HOMEBREW_PREFIX/bin:$PATH"
echo "::add-path::$HOMEBREW_PREFIX/bin"
fi fi
export PATH="$HOMEBREW_PREFIX/bin:$PATH"
echo "::add-path::$HOMEBREW_PREFIX/bin"
cd "$HOMEBREW_REPOSITORY" cd "$HOMEBREW_REPOSITORY"
rm -rf "$GITHUB_WORKSPACE" rm -rf "$GITHUB_WORKSPACE"
ln -s "$HOMEBREW_REPOSITORY" "$GITHUB_WORKSPACE" ln -s "$HOMEBREW_REPOSITORY" "$GITHUB_WORKSPACE"
@ -65,11 +66,11 @@ jobs:
# Cleanup some Linux `brew doctor` failures # Cleanup some Linux `brew doctor` failures
sudo rm -rf /usr/local/include/node/ sudo rm -rf /usr/local/include/node/
else else
# Allow Xcode to be outdated
export HOMEBREW_GITHUB_ACTIONS=1
# Link old gettext (otherwise `brew doctor` is sad) # Link old gettext (otherwise `brew doctor` is sad)
brew link gettext brew link gettext
# remove deleted formula
brew uninstall --force python@2
fi fi
brew doctor brew doctor
@ -92,7 +93,6 @@ jobs:
- name: Install taps - name: Install taps
run: | run: |
# Install taps needed for 'brew tests' and 'brew man' # Install taps needed for 'brew tests' and 'brew man'
export HOMEBREW_NO_AUTO_UPDATE=1
cd "$(brew --repo)" cd "$(brew --repo)"
brew tap homebrew/bundle brew tap homebrew/bundle
brew update-reset Library/Taps/homebrew/homebrew-bundle brew update-reset Library/Taps/homebrew/homebrew-bundle
@ -136,7 +136,6 @@ jobs:
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# set variables for coverage reporting # set variables for coverage reporting
HOMEBREW_GITHUB_ACTIONS: 1
HOMEBREW_CI_NAME: github-actions HOMEBREW_CI_NAME: github-actions
HOMEBREW_COVERALLS_REPO_TOKEN: 3F6U6ZqctoNJwKyREremsqMgpU3qYgxFk HOMEBREW_COVERALLS_REPO_TOKEN: 3F6U6ZqctoNJwKyREremsqMgpU3qYgxFk
@ -174,30 +173,22 @@ jobs:
- name: Build Docker image - name: Build Docker image
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
run: | run: docker build -t brew --build-arg=version=16.04 .
docker pull homebrew/brew
docker-compose -f Dockerfile.yml build sut
- name: Run brew test-bot - name: Run brew test-bot
run: | run: |
if [ "$RUNNER_OS" = "Linux" ]; then if [ "$RUNNER_OS" = "Linux" ]; then
docker-compose -f Dockerfile.yml run --rm -v $GITHUB_WORKSPACE:/tmp/test-bot sut docker run --rm brew brew test-bot
docker tag homebrew_sut brew
else else
brew test-bot brew test-bot
fi fi
- name: Deploy the latest Docker image - name: Deploy the Docker image to GitHub and Docker Hub
if: matrix.os == 'ubuntu-latest' && github.ref == 'refs/heads/master' if: matrix.os == 'ubuntu-latest' && github.ref == 'refs/heads/master'
run: | run: |
docker login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}} docker login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}}
docker tag brew docker.pkg.github.com/homebrew/brew/brew docker tag brew "docker.pkg.github.com/homebrew/brew/ubuntu16.04:master"
docker push docker.pkg.github.com/homebrew/brew/brew docker push "docker.pkg.github.com/homebrew/brew/ubuntu16.04:master"
docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}}
- name: Deploy the tagged Docker image docker tag brew "homebrew/ubuntu16.04:master"
if: matrix.os == 'ubuntu-latest' && startsWith(github.ref, 'refs/tags/') docker push "homebrew/ubuntu16.04:master"
run: |
docker login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}}
v=${GITHUB_REF:10}
docker tag brew "docker.pkg.github.com/homebrew/brew/brew:$v"
docker push "docker.pkg.github.com/homebrew/brew/brew:$v"

4
.gitignore vendored
View File

@ -18,6 +18,7 @@
/Library/Homebrew/vendor/portable-ruby /Library/Homebrew/vendor/portable-ruby
/Library/Taps /Library/Taps
/Library/PinnedTaps /Library/PinnedTaps
/Library/Homebrew/.byebug_history
# Ignore Bundler files # Ignore Bundler files
**/.bundle/bin **/.bundle/bin
@ -119,6 +120,7 @@
**/vendor/bundle/ruby/*/gems/rspec-support-*/ **/vendor/bundle/ruby/*/gems/rspec-support-*/
**/vendor/bundle/ruby/*/gems/rspec-wait-*/ **/vendor/bundle/ruby/*/gems/rspec-wait-*/
**/vendor/bundle/ruby/*/gems/rubocop-0*/ **/vendor/bundle/ruby/*/gems/rubocop-0*/
**/vendor/bundle/ruby/*/gems/rubocop-ast-*/
**/vendor/bundle/ruby/*/gems/ruby-prof-*/ **/vendor/bundle/ruby/*/gems/ruby-prof-*/
**/vendor/bundle/ruby/*/gems/ruby-progressbar-*/ **/vendor/bundle/ruby/*/gems/ruby-progressbar-*/
**/vendor/bundle/ruby/*/gems/simplecov-*/ **/vendor/bundle/ruby/*/gems/simplecov-*/
@ -131,6 +133,7 @@
**/vendor/bundle/ruby/*/gems/unf-*/ **/vendor/bundle/ruby/*/gems/unf-*/
**/vendor/bundle/ruby/*/gems/unicode-display_width-*/ **/vendor/bundle/ruby/*/gems/unicode-display_width-*/
**/vendor/bundle/ruby/*/gems/webrobots-*/ **/vendor/bundle/ruby/*/gems/webrobots-*/
**/vendor/bundle/ruby/*/gems/byebug-*/
# Ignore `bin` contents (again). # Ignore `bin` contents (again).
/bin /bin
@ -151,6 +154,7 @@
/docs/vendor /docs/vendor
# Unignore our root-level metadata files. # Unignore our root-level metadata files.
!/.dockerignore
!/.editorconfig !/.editorconfig
!/.gitignore !/.gitignore
!/.yardopts !/.yardopts

View File

@ -1,5 +1,6 @@
FROM ubuntu:xenial ARG version=20.04
LABEL maintainer="Shaun Jackman <sjackman@gmail.com>" FROM ubuntu:$version
ARG DEBIAN_FRONTEND=noninteractive
# hadolint ignore=DL3008 # hadolint ignore=DL3008
RUN apt-get update \ RUN apt-get update \
@ -14,6 +15,7 @@ RUN apt-get update \
fonts-dejavu-core \ fonts-dejavu-core \
g++ \ g++ \
git \ git \
less \
libz-dev \ libz-dev \
locales \ locales \
make \ make \
@ -23,29 +25,23 @@ RUN apt-get update \
sudo \ sudo \
uuid-runtime \ uuid-runtime \
tzdata \ tzdata \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/* \
&& localedef -i en_US -f UTF-8 en_US.UTF-8 \
RUN localedef -i en_US -f UTF-8 en_US.UTF-8 \
&& useradd -m -s /bin/bash linuxbrew \ && useradd -m -s /bin/bash linuxbrew \
&& echo 'linuxbrew ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers && echo 'linuxbrew ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers
COPY . /home/linuxbrew/.linuxbrew/Homebrew COPY . /home/linuxbrew/.linuxbrew/Homebrew
ARG FORCE_REBUILD ENV PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
WORKDIR /home/linuxbrew
# hadolint ignore=DL3003 # hadolint ignore=DL3003
RUN cd /home/linuxbrew/.linuxbrew \ RUN cd /home/linuxbrew/.linuxbrew \
&& mkdir -p bin etc include lib opt sbin share var/homebrew/linked Cellar \ && mkdir -p bin etc include lib opt sbin share var/homebrew/linked Cellar \
&& ln -s ../Homebrew/bin/brew /home/linuxbrew/.linuxbrew/bin/ \ && ln -s ../Homebrew/bin/brew /home/linuxbrew/.linuxbrew/bin/ \
&& cd /home/linuxbrew/.linuxbrew/Homebrew \ && git -C /home/linuxbrew/.linuxbrew/Homebrew remote set-url origin https://github.com/Homebrew/brew \
&& git remote set-url origin https://github.com/Homebrew/brew && HOMEBREW_NO_ANALYTICS=1 HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/core \
WORKDIR /home/linuxbrew
ENV PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH \
SHELL=/bin/bash
# Install portable-ruby, tap homebrew/core, install audit gems, and cleanup
RUN HOMEBREW_NO_ANALYTICS=1 HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/core \
&& chown -R linuxbrew: /home/linuxbrew/.linuxbrew \
&& chmod -R g+w,o-w /home/linuxbrew/.linuxbrew \
&& rm -rf ~/.cache \
&& brew install-bundler-gems \ && brew install-bundler-gems \
&& brew cleanup && brew cleanup \
&& rm -rf ~/.cache \
&& chown -R linuxbrew: /home/linuxbrew/.linuxbrew \
&& chmod -R g+w,o-w /home/linuxbrew/.linuxbrew

View File

@ -1,17 +0,0 @@
version: '3.7'
services:
sut:
build:
context: .
cache_from:
- homebrew/brew
args:
- FORCE_REBUILD=1
command:
- sh
- -xc
- |
/home/linuxbrew/.linuxbrew/bin/brew test-bot
status=$$?
exit $$status

View File

@ -15,12 +15,14 @@ Style/DisableCopsWithinSourceCodeDirective:
# Intentionally disabled as it doesn't fit with our code style. # Intentionally disabled as it doesn't fit with our code style.
RSpec/AnyInstance: RSpec/AnyInstance:
Enabled: false Enabled: false
RSpec/FilePath:
Enabled: false
RSpec/ImplicitBlockExpectation: RSpec/ImplicitBlockExpectation:
Enabled: false Enabled: false
RSpec/SubjectStub: RSpec/SubjectStub:
Enabled: false Enabled: false
# TODO: try to enable these (also requires fixing Homebrew/bundle) # TODO: try to enable these
RSpec/ContextWording: RSpec/ContextWording:
Enabled: false Enabled: false
RSpec/DescribeClass: RSpec/DescribeClass:
@ -34,7 +36,7 @@ RSpec/RepeatedDescription:
RSpec/RepeatedExampleGroupDescription: RSpec/RepeatedExampleGroupDescription:
Enabled: false Enabled: false
# TODO: try to reduce these (also requires fixing Homebrew/bundle) # TODO: try to reduce these
RSpec/ExampleLength: RSpec/ExampleLength:
Max: 75 Max: 75
RSpec/MultipleExpectations: RSpec/MultipleExpectations:

View File

@ -46,6 +46,8 @@ Metrics/AbcSize:
Metrics/BlockLength: Metrics/BlockLength:
Enabled: true Enabled: true
Max: 1100 Max: 1100
Exclude:
- 'test/formula_spec.rb'
Metrics/BlockNesting: Metrics/BlockNesting:
Enabled: true Enabled: true
Max: 5 Max: 5

View File

@ -3,6 +3,7 @@
source "https://rubygems.org" source "https://rubygems.org"
# installed gems # installed gems
gem "byebug"
gem "coveralls", "~> 0.8", require: false gem "coveralls", "~> 0.8", require: false
gem "parallel_tests" gem "parallel_tests"
gem "ronn", require: false gem "ronn", require: false

View File

@ -1,13 +1,14 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
activesupport (6.0.2.2) activesupport (6.0.3.1)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
zeitwerk (~> 2.2) zeitwerk (~> 2.2, >= 2.2.2)
ast (2.4.0) ast (2.4.0)
byebug (11.1.3)
concurrent-ruby (1.1.6) concurrent-ruby (1.1.6)
connection_pool (2.2.2) connection_pool (2.2.2)
coveralls (0.8.23) coveralls (0.8.23)
@ -25,7 +26,6 @@ GEM
domain_name (~> 0.5) domain_name (~> 0.5)
i18n (1.8.2) i18n (1.8.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
jaro_winkler (1.5.4)
json (2.3.0) json (2.3.0)
mechanize (2.7.6) mechanize (2.7.6)
domain_name (~> 0.5, >= 0.5.1) domain_name (~> 0.5, >= 0.5.1)
@ -38,9 +38,9 @@ GEM
webrobots (>= 0.0.9, < 0.2) webrobots (>= 0.0.9, < 0.2)
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.0425) mime-types-data (3.2020.0512)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.14.0) minitest (5.14.1)
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.0) net-http-persistent (4.0.0)
@ -65,9 +65,9 @@ GEM
rspec-core (~> 3.9.0) rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0) rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.9.0) rspec-mocks (~> 3.9.0)
rspec-core (3.9.1) rspec-core (3.9.2)
rspec-support (~> 3.9.1) rspec-support (~> 3.9.3)
rspec-expectations (3.9.1) rspec-expectations (3.9.2)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0) rspec-support (~> 3.9.0)
rspec-its (1.3.0) rspec-its (1.3.0)
@ -78,18 +78,20 @@ GEM
rspec-support (~> 3.9.0) rspec-support (~> 3.9.0)
rspec-retry (0.6.2) rspec-retry (0.6.2)
rspec-core (> 3.3) rspec-core (> 3.3)
rspec-support (3.9.2) rspec-support (3.9.3)
rspec-wait (0.0.9) rspec-wait (0.0.9)
rspec (>= 3, < 4) rspec (>= 3, < 4)
rubocop (0.82.0) rubocop (0.84.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.7.0.1) parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
rexml rexml
rubocop-ast (>= 0.0.3)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0) unicode-display_width (>= 1.4.0, < 2.0)
rubocop-performance (1.5.2) rubocop-ast (0.0.3)
parser (>= 2.7.0.1)
rubocop-performance (1.6.0)
rubocop (>= 0.71.0) rubocop (>= 0.71.0)
rubocop-rspec (1.39.0) rubocop-rspec (1.39.0)
rubocop (>= 0.68.1) rubocop (>= 0.68.1)
@ -105,7 +107,7 @@ GEM
tins (~> 1.0) tins (~> 1.0)
thor (1.0.1) thor (1.0.1)
thread_safe (0.3.6) thread_safe (0.3.6)
tins (1.24.1) tins (1.25.0)
sync sync
tzinfo (1.2.7) tzinfo (1.2.7)
thread_safe (~> 0.1) thread_safe (~> 0.1)
@ -121,6 +123,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
activesupport activesupport
byebug
concurrent-ruby concurrent-ruby
coveralls (~> 0.8) coveralls (~> 0.8)
mechanize mechanize

View File

@ -106,12 +106,12 @@ class Bintray
formula_packaged = {} formula_packaged = {}
bottles_hash.each do |formula_name, bottle_hash| bottles_hash.each do |formula_name, bottle_hash|
version = bottle_hash["formula"]["pkg_version"] version = ERB::Util.url_encode(bottle_hash["formula"]["pkg_version"])
bintray_package = bottle_hash["bintray"]["package"] bintray_package = bottle_hash["bintray"]["package"]
bintray_repo = bottle_hash["bintray"]["repository"] bintray_repo = bottle_hash["bintray"]["repository"]
bottle_hash["bottle"]["tags"].each do |_tag, tag_hash| bottle_hash["bottle"]["tags"].each do |_tag, tag_hash|
filename = tag_hash["filename"] filename = tag_hash["filename"] # URL encoded in Bottle::Filename#bintray
sha256 = tag_hash["sha256"] sha256 = tag_hash["sha256"]
odebug "Checking remote file #{@bintray_org}/#{bintray_repo}/#{filename}" odebug "Checking remote file #{@bintray_org}/#{bintray_repo}/#{filename}"
@ -132,7 +132,7 @@ class Bintray
formula_packaged[formula_name] = true formula_packaged[formula_name] = true
end end
odebug "Uploading #{@bintray_org}/#{bintray_repo}/#{bintray_package}/#{version}/#{tag_hash["local_filename"]}" odebug "Uploading #{@bintray_org}/#{bintray_repo}/#{bintray_package}/#{version}/#{filename}"
upload(tag_hash["local_filename"], upload(tag_hash["local_filename"],
repo: bintray_repo, repo: bintray_repo,
package: bintray_package, package: bintray_package,

View File

@ -93,6 +93,30 @@ case "$HOMEBREW_SYSTEM" in
Linux) HOMEBREW_LINUX="1" ;; Linux) HOMEBREW_LINUX="1" ;;
esac esac
if [[ -n "$HOMEBREW_FORCE_BREWED_CURL" &&
-x "$HOMEBREW_PREFIX/opt/curl/bin/curl" ]] &&
"$HOMEBREW_PREFIX/opt/curl/bin/curl" --version >/dev/null
then
HOMEBREW_CURL="$HOMEBREW_PREFIX/opt/curl/bin/curl"
elif [[ -n "$HOMEBREW_DEVELOPER" && -x "$HOMEBREW_CURL_PATH" ]]
then
HOMEBREW_CURL="$HOMEBREW_CURL_PATH"
else
HOMEBREW_CURL="curl"
fi
if [[ -n "$HOMEBREW_FORCE_BREWED_GIT" &&
-x "$HOMEBREW_PREFIX/opt/git/bin/git" ]] &&
"$HOMEBREW_PREFIX/opt/git/bin/git" --version >/dev/null
then
HOMEBREW_GIT="$HOMEBREW_PREFIX/opt/git/bin/git"
elif [[ -n "$HOMEBREW_DEVELOPER" && -x "$HOMEBREW_GIT_PATH" ]]
then
HOMEBREW_GIT="$HOMEBREW_GIT_PATH"
else
HOMEBREW_GIT="git"
fi
if [[ -n "$HOMEBREW_MACOS" ]] if [[ -n "$HOMEBREW_MACOS" ]]
then then
HOMEBREW_PROCESSOR="$(uname -p)" HOMEBREW_PROCESSOR="$(uname -p)"
@ -159,24 +183,44 @@ else
# Ensure the system Curl is a version that supports modern HTTPS certificates. # Ensure the system Curl is a version that supports modern HTTPS certificates.
HOMEBREW_MINIMUM_CURL_VERSION="7.41.0" HOMEBREW_MINIMUM_CURL_VERSION="7.41.0"
system_curl_version_output="$($(command -v curl) --version 2>/dev/null)" curl_version_output="$($HOMEBREW_CURL --version 2>/dev/null)"
system_curl_name_and_version="${system_curl_version_output%% (*}" curl_name_and_version="${curl_version_output%% (*}"
if [[ $(numeric "${system_curl_name_and_version##* }") -lt $(numeric "$HOMEBREW_MINIMUM_CURL_VERSION") ]] if [[ $(numeric "${curl_name_and_version##* }") -lt $(numeric "$HOMEBREW_MINIMUM_CURL_VERSION") ]]
then then
HOMEBREW_SYSTEM_CURL_TOO_OLD="1" if [[ -z $HOMEBREW_CURL_PATH ]]; then
HOMEBREW_FORCE_BREWED_CURL="1" HOMEBREW_SYSTEM_CURL_TOO_OLD=1
HOMEBREW_FORCE_BREWED_CURL=1
else
odie <<EOS
The version of cURL that you provided to Homebrew using HOMEBREW_CURL_PATH is too old.
Minimum required version: ${HOMEBREW_MINIMUM_CURL_VERSION}.
Your cURL version: ${curl_name_and_version##* }.
Please point Homebrew to cURL ${HOMEBREW_MINIMUM_CURL_VERSION} or newer
or unset HOMEBREW_CURL_PATH variable.
EOS
fi
fi fi
# Ensure the system Git is at or newer than the minimum required version. # Ensure the system Git is at or newer than the minimum required version.
# Git 2.7.4 is the version of git on Ubuntu 16.04 LTS (Xenial Xerus). # Git 2.7.4 is the version of git on Ubuntu 16.04 LTS (Xenial Xerus).
HOMEBREW_MINIMUM_GIT_VERSION="2.7.0" HOMEBREW_MINIMUM_GIT_VERSION="2.7.0"
system_git_version_output="$($(command -v git) --version 2>/dev/null)" git_version_output="$($HOMEBREW_GIT --version 2>/dev/null)"
# $extra is intentionally discarded. # $extra is intentionally discarded.
# shellcheck disable=SC2034 # shellcheck disable=SC2034
IFS=. read -r major minor micro build extra <<< "${system_git_version_output##* }" IFS=. read -r major minor micro build extra <<< "${git_version_output##* }"
if [[ $(numeric "$major.$minor.$micro.$build") -lt $(numeric "$HOMEBREW_MINIMUM_GIT_VERSION") ]] if [[ $(numeric "$major.$minor.$micro.$build") -lt $(numeric "$HOMEBREW_MINIMUM_GIT_VERSION") ]]
then then
HOMEBREW_FORCE_BREWED_GIT="1" if [[ -z $HOMEBREW_GIT_PATH ]]; then
HOMEBREW_FORCE_BREWED_GIT="1"
else
odie <<EOS
The version of Git that you provided to Homebrew using HOMEBREW_GIT_PATH is too old.
Minimum required version: ${HOMEBREW_MINIMUM_GIT_VERSION}.
Your Git version: $major.$minor.$micro.$build.
Please point Homebrew to Git ${HOMEBREW_MINIMUM_CURL_VERSION} or newer
or unset HOMEBREW_GIT_PATH variable.
EOS
fi
fi fi
CACHE_HOME="${XDG_CACHE_HOME:-${HOME}/.cache}" CACHE_HOME="${XDG_CACHE_HOME:-${HOME}/.cache}"
@ -198,30 +242,6 @@ HOMEBREW_CACHE="${HOMEBREW_CACHE:-${HOMEBREW_DEFAULT_CACHE}}"
HOMEBREW_LOGS="${HOMEBREW_LOGS:-${HOMEBREW_DEFAULT_LOGS}}" HOMEBREW_LOGS="${HOMEBREW_LOGS:-${HOMEBREW_DEFAULT_LOGS}}"
HOMEBREW_TEMP="${HOMEBREW_TEMP:-${HOMEBREW_DEFAULT_TEMP}}" HOMEBREW_TEMP="${HOMEBREW_TEMP:-${HOMEBREW_DEFAULT_TEMP}}"
if [[ -n "$HOMEBREW_FORCE_BREWED_CURL" &&
-x "$HOMEBREW_PREFIX/opt/curl/bin/curl" ]] &&
"$HOMEBREW_PREFIX/opt/curl/bin/curl" --version >/dev/null
then
HOMEBREW_CURL="$HOMEBREW_PREFIX/opt/curl/bin/curl"
elif [[ -n "$HOMEBREW_DEVELOPER" && -x "$HOMEBREW_CURL_PATH" ]]
then
HOMEBREW_CURL="$HOMEBREW_CURL_PATH"
else
HOMEBREW_CURL="curl"
fi
if [[ -n "$HOMEBREW_FORCE_BREWED_GIT" &&
-x "$HOMEBREW_PREFIX/opt/git/bin/git" ]] &&
"$HOMEBREW_PREFIX/opt/git/bin/git" --version >/dev/null
then
HOMEBREW_GIT="$HOMEBREW_PREFIX/opt/git/bin/git"
elif [[ -n "$HOMEBREW_DEVELOPER" && -x "$HOMEBREW_GIT_PATH" ]]
then
HOMEBREW_GIT="$HOMEBREW_GIT_PATH"
else
HOMEBREW_GIT="git"
fi
HOMEBREW_USER_AGENT="$HOMEBREW_PRODUCT/$HOMEBREW_USER_AGENT_VERSION ($HOMEBREW_SYSTEM; $HOMEBREW_PROCESSOR $HOMEBREW_OS_USER_AGENT_VERSION)" HOMEBREW_USER_AGENT="$HOMEBREW_PRODUCT/$HOMEBREW_USER_AGENT_VERSION ($HOMEBREW_SYSTEM; $HOMEBREW_PROCESSOR $HOMEBREW_OS_USER_AGENT_VERSION)"
curl_version_output="$("$HOMEBREW_CURL" --version 2>/dev/null)" curl_version_output="$("$HOMEBREW_CURL" --version 2>/dev/null)"
curl_name_and_version="${curl_version_output%% (*}" curl_name_and_version="${curl_version_output%% (*}"

View File

@ -52,6 +52,8 @@ class Build
Requirement.prune Requirement.prune
elsif req.prune_if_build_and_not_dependent?(dependent, formula) elsif req.prune_if_build_and_not_dependent?(dependent, formula)
Requirement.prune Requirement.prune
elsif req.test?
Requirement.prune
end end
end end
end end
@ -65,6 +67,8 @@ class Build
Dependency.prune Dependency.prune
elsif dep.build? elsif dep.build?
Dependency.keep_but_prune_recursive_deps Dependency.keep_but_prune_recursive_deps
elsif dep.test?
Dependency.prune
end end
end end
end end
@ -114,7 +118,9 @@ class Build
with_env(new_env) do with_env(new_env) do
formula.extend(Debrew::Formula) if ARGV.debug? formula.extend(Debrew::Formula) if ARGV.debug?
formula.brew do |_formula, staging| formula.update_head_version
formula.brew(fetch: false) do |_formula, staging|
# For head builds, HOMEBREW_FORMULA_PREFIX should include the commit, # For head builds, HOMEBREW_FORMULA_PREFIX should include the commit,
# which is not known until after the formula has been staged. # which is not known until after the formula has been staged.
ENV["HOMEBREW_FORMULA_PREFIX"] = formula.prefix ENV["HOMEBREW_FORMULA_PREFIX"] = formula.prefix

View File

@ -89,7 +89,7 @@ module Cask
args: ["list", service], args: ["list", service],
sudo: with_sudo, print_stderr: false sudo: with_sudo, print_stderr: false
).stdout ).stdout
if plist_status.match?(/^\{/) if plist_status.start_with?("{")
command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo) command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo)
sleep 1 sleep 1
end end

View File

@ -145,7 +145,7 @@ module Cask
command, args = detect_internal_command(*args) || detect_external_command(*args) || [NullCommand.new, args] command, args = detect_internal_command(*args) || detect_external_command(*args) || [NullCommand.new, args]
if help? if help?
puts command.help Help.new(command.command_name).run
else else
command.run(*args) command.run(*args)
end end
@ -228,7 +228,7 @@ module Cask
end end
def run(*) def run(*)
exec @path, *ARGV[1..-1] exec @path, *ARGV[1..]
end end
end end
@ -243,6 +243,10 @@ module Cask
$stderr.puts $stderr.puts
$stderr.puts Help.usage $stderr.puts Help.usage
end end
def help
run
end
end end
end end
end end

View File

@ -37,6 +37,7 @@ module Cask
end end
attr_accessor :args attr_accessor :args
private :args= private :args=
def initialize(*args) def initialize(*args)

View File

@ -3,17 +3,26 @@
module Cask module Cask
class Cmd class Cmd
class Help < AbstractCommand class Help < AbstractCommand
def initialize(*)
super
return if args.empty?
raise ArgumentError, "#{self.class.command_name} does not take arguments."
end
def run def run
puts self.class.purpose if args.empty?
puts puts self.class.purpose
puts self.class.usage puts
puts self.class.usage
elsif args.count == 1
command_name = args.first
unless command = self.class.commands[command_name]
raise "No help information found for command '#{command_name}'."
end
if command.respond_to?(:usage)
puts command.usage
else
puts command.help
end
else
raise ArgumentError, "#{self.class.command_name} only takes up to one argument."
end
end end
def self.purpose def self.purpose
@ -23,6 +32,10 @@ module Cask
EOS EOS
end end
def self.commands
Cmd.command_classes.select(&:visible?).map { |klass| [klass.command_name, klass] }.to_h
end
def self.usage def self.usage
max_command_len = Cmd.commands.map(&:length).max max_command_len = Cmd.commands.map(&:length).max

View File

@ -46,6 +46,7 @@ module Cask
def self.info(cask) def self.info(cask)
puts get_info(cask) puts get_info(cask)
::Utils::Analytics.cask_output(cask)
end end
def self.title_info(cask) def self.title_info(cask)

View File

@ -33,9 +33,11 @@ module Cask
option "--inspect", :inspect, false option "--inspect", :inspect, false
attr_accessor :format attr_accessor :format
private :format, :format= private :format, :format=
attr_accessor :stanza attr_accessor :stanza
private :stanza, :stanza= private :stanza, :stanza=
def initialize(*) def initialize(*)

View File

@ -7,11 +7,6 @@ module Cask
option "--versions", :versions, false option "--versions", :versions, false
option "--full-name", :full_name, false option "--full-name", :full_name, false
option "-l", (lambda do |*|
one = true # rubocop:disable Lint/UselessAssignment
opoo "Option -l is obsolete! Implying option -1."
end)
def run def run
args.any? ? list : list_installed args.any? ? list : list_installed
end end

View File

@ -368,6 +368,7 @@ module Cask
fi.installed_on_request = false fi.installed_on_request = false
fi.show_header = true fi.show_header = true
fi.verbose = verbose? fi.verbose = verbose?
fi.fetch
fi.prelude fi.prelude
fi.install fi.install
fi.finish fi.finish

View File

@ -142,14 +142,18 @@ module Homebrew
cleanup = Cleanup.new cleanup = Cleanup.new
if cleanup.periodic_clean_due? if cleanup.periodic_clean_due?
cleanup.periodic_clean! cleanup.periodic_clean!
elsif f.installed? elsif f.latest_version_installed?
cleanup.cleanup_formula(f) cleanup.cleanup_formula(f)
end end
end end
def periodic_clean_due? def periodic_clean_due?
return false if Homebrew::EnvConfig.no_install_cleanup? return false if Homebrew::EnvConfig.no_install_cleanup?
return true unless PERIODIC_CLEAN_FILE.exist?
unless PERIODIC_CLEAN_FILE.exist?
FileUtils.touch PERIODIC_CLEAN_FILE
return false
end
PERIODIC_CLEAN_FILE.mtime < CLEANUP_DEFAULT_DAYS.days.ago PERIODIC_CLEAN_FILE.mtime < CLEANUP_DEFAULT_DAYS.days.ago
end end

View File

@ -5,56 +5,54 @@ require "ostruct"
module Homebrew module Homebrew
module CLI module CLI
class Args < OpenStruct class Args < OpenStruct
attr_reader :processed_options, :args_parsed attr_reader :options_only, :flags_only
# undefine tap to allow --tap argument # undefine tap to allow --tap argument
undef tap undef tap
def initialize def initialize(argv = ARGV.dup.freeze, set_default_args: false)
super super()
self[:remaining] = []
self[:cmdline_args] = ARGV.dup.freeze
@args_parsed = false
@processed_options = [] @processed_options = []
@options_only = args_options_only(argv)
@flags_only = args_flags_only(argv)
# Can set these because they will be overwritten by freeze_named_args!
# (whereas other values below will only be overwritten if passed).
self[:named_args] = argv.reject { |arg| arg.start_with?("-") }
# Set values needed before Parser#parse has been run.
return unless set_default_args
self[:build_from_source?] = argv.include?("--build-from-source") || argv.include?("-s")
self[:build_bottle?] = argv.include?("--build-bottle")
self[:force_bottle?] = argv.include?("--force-bottle")
self[:HEAD?] = argv.include?("--HEAD")
self[:devel?] = argv.include?("--devel")
self[:universal?] = argv.include?("--universal")
end
def freeze_named_args!(named_args)
# Reset cache values reliant on named_args
@formulae = nil
@resolved_formulae = nil
@formulae_paths = nil
@casks = nil
@kegs = nil
self[:named_args] = named_args
self[:named_args].freeze
end end
def freeze_processed_options!(processed_options) def freeze_processed_options!(processed_options)
# Reset cache values reliant on processed_options
@cli_args = nil
@processed_options += processed_options @processed_options += processed_options
@processed_options.freeze @processed_options.freeze
@args_parsed = true
end
def option_to_name(option) @options_only = args_options_only(cli_args)
option.sub(/\A--?/, "") @flags_only = args_flags_only(cli_args)
.tr("-", "_")
end
def cli_args
return @cli_args if @cli_args
@cli_args = []
processed_options.each do |short, long|
option = long || short
switch = "#{option_to_name(option)}?".to_sym
flag = option_to_name(option).to_sym
if @table[switch] == true || @table[flag] == true
@cli_args << option
elsif @table[flag].instance_of? String
@cli_args << option + "=" + @table[flag]
elsif @table[flag].instance_of? Array
@cli_args << option + "=" + @table[flag].join(",")
end
end
@cli_args
end
def options_only
@options_only ||= cli_args.select { |arg| arg.start_with?("-") }
end
def flags_only
@flags_only ||= cli_args.select { |arg| arg.start_with?("--") }
end end
def passthrough def passthrough
@ -62,7 +60,7 @@ module Homebrew
end end
def named def named
remaining named_args || []
end end
def no_named? def no_named?
@ -74,46 +72,50 @@ module Homebrew
def collect_build_args def collect_build_args
build_flags = [] build_flags = []
build_flags << "--HEAD" if head build_flags << "--HEAD" if HEAD?
build_flags << "--universal" if build_universal build_flags << "--universal" if build_universal?
build_flags << "--build-bottle" if build_bottle build_flags << "--build-bottle" if build_bottle?
build_flags << "--build-from-source" if build_from_source build_flags << "--build-from-source" if build_from_source?
build_flags build_flags
end end
def formulae def formulae
require "formula" require "formula"
@formulae ||= (downcased_unique_named - casks).map do |name| @formulae ||= (downcased_unique_named - casks).map do |name|
if name.include?("/") || File.exist?(name) if name.include?("/") || File.exist?(name)
Formulary.factory(name, spec) Formulary.factory(name, spec)
else else
Formulary.find_with_priority(name, spec) Formulary.find_with_priority(name, spec)
end end
end.uniq(&:name) end.uniq(&:name).freeze
end end
def resolved_formulae def resolved_formulae
require "formula" require "formula"
@resolved_formulae ||= (downcased_unique_named - casks).map do |name| @resolved_formulae ||= (downcased_unique_named - casks).map do |name|
Formulary.resolve(name, spec: spec(nil)) Formulary.resolve(name, spec: spec(nil))
end.uniq(&:name) end.uniq(&:name).freeze
end end
def formulae_paths def formulae_paths
@formulae_paths ||= (downcased_unique_named - casks).map do |name| @formulae_paths ||= (downcased_unique_named - casks).map do |name|
Formulary.path(name) Formulary.path(name)
end.uniq end.uniq.freeze
end end
def casks def casks
@casks ||= downcased_unique_named.grep HOMEBREW_CASK_TAP_CASK_REGEX @casks ||= downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX)
.freeze
end end
def kegs def kegs
require "keg" require "keg"
require "formula" require "formula"
require "missing_formula" require "missing_formula"
@kegs ||= downcased_unique_named.map do |name| @kegs ||= downcased_unique_named.map do |name|
raise UsageError if name.empty? raise UsageError if name.empty?
@ -158,7 +160,7 @@ module Homebrew
Please delete (with rm -rf!) all but one and then try again. Please delete (with rm -rf!) all but one and then try again.
EOS EOS
end end
end end.freeze
end end
def build_stable? def build_stable?
@ -168,39 +170,56 @@ module Homebrew
# Whether a given formula should be built from source during the current # Whether a given formula should be built from source during the current
# installation run. # installation run.
def build_formula_from_source?(f) def build_formula_from_source?(f)
return false if !build_from_source && !build_bottle return false if !build_from_source? && !build_bottle?
formulae.any? { |args_f| args_f.full_name == f.full_name } formulae.any? { |args_f| args_f.full_name == f.full_name }
end end
def build_from_source def include_formula_test_deps?(f)
return true if args_parsed && (build_from_source? || s?) return false unless include_test?
cmdline_args.include?("--build-from-source") || cmdline_args.include?("-s") formulae.any? { |args_f| args_f.full_name == f.full_name }
end
def build_bottle
return true if args_parsed && build_bottle?
cmdline_args.include?("--build-bottle")
end
def force_bottle
return true if args_parsed && force_bottle?
cmdline_args.include?("--force-bottle")
end end
private private
def option_to_name(option)
option.sub(/\A--?/, "")
.tr("-", "_")
end
def cli_args
return @cli_args if @cli_args
@cli_args = []
@processed_options.each do |short, long|
option = long || short
switch = "#{option_to_name(option)}?".to_sym
flag = option_to_name(option).to_sym
if @table[switch] == true || @table[flag] == true
@cli_args << option
elsif @table[flag].instance_of? String
@cli_args << option + "=" + @table[flag]
elsif @table[flag].instance_of? Array
@cli_args << option + "=" + @table[flag].join(",")
end
end
@cli_args.freeze
end
def args_options_only(args)
args.select { |arg| arg.start_with?("-") }
.freeze
end
def args_flags_only(args)
args.select { |arg| arg.start_with?("--") }
.freeze
end
def downcased_unique_named def downcased_unique_named
# Only lowercase names, not paths, bottle filenames or URLs # Only lowercase names, not paths, bottle filenames or URLs
arguments = if args_parsed named.map do |arg|
named
else
cmdline_args.reject { |arg| arg.start_with?("-") }
end
arguments.map do |arg|
if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg) if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
arg arg
else else
@ -209,28 +228,10 @@ module Homebrew
end.uniq end.uniq
end end
def head
return true if args_parsed && HEAD?
cmdline_args.include?("--HEAD")
end
def devel
return true if args_parsed && devel?
cmdline_args.include?("--devel")
end
def build_universal
return true if args_parsed && universal?
cmdline_args.include?("--universal")
end
def spec(default = :stable) def spec(default = :stable)
if head if HEAD?
:head :head
elsif devel elsif devel?
:devel :devel
else else
default default

View File

@ -3,6 +3,7 @@
require "cli/args" require "cli/args"
require "optparse" require "optparse"
require "set" require "set"
require "formula"
COMMAND_DESC_WIDTH = 80 COMMAND_DESC_WIDTH = 80
OPTION_DESC_WIDTH = 43 OPTION_DESC_WIDTH = 43
@ -12,8 +13,8 @@ module Homebrew
class Parser class Parser
attr_reader :processed_options, :hide_from_man_page attr_reader :processed_options, :hide_from_man_page
def self.parse(args = ARGV, allow_no_named_args: false, &block) def self.parse(argv = ARGV.dup.freeze, allow_no_named_args: false, &block)
new(args, &block).parse(args, allow_no_named_args: allow_no_named_args) new(argv, &block).parse(allow_no_named_args: allow_no_named_args)
end end
def self.from_cmd_path(cmd_path) def self.from_cmd_path(cmd_path)
@ -37,9 +38,10 @@ module Homebrew
} }
end end
def initialize(&block) def initialize(argv = ARGV.dup.freeze, &block)
@parser = OptionParser.new @parser = OptionParser.new
@args = Homebrew::CLI::Args.new @argv = argv
@args = Homebrew::CLI::Args.new(@argv)
@constraints = [] @constraints = []
@conflicts = [] @conflicts = []
@ -152,21 +154,22 @@ module Homebrew
@parser.to_s @parser.to_s
end end
def parse(cmdline_args = ARGV, allow_no_named_args: false) def parse(argv = @argv, allow_no_named_args: false)
raise "Arguments were already parsed!" if @args_parsed raise "Arguments were already parsed!" if @args_parsed
begin begin
named_args = @parser.parse(cmdline_args) named_args = @parser.parse(argv)
rescue OptionParser::InvalidOption => e rescue OptionParser::InvalidOption => e
$stderr.puts generate_help_text $stderr.puts generate_help_text
raise e raise e
end end
check_constraint_violations check_constraint_violations
check_named_args(named_args, allow_no_named_args: allow_no_named_args) check_named_args(named_args, allow_no_named_args: allow_no_named_args)
@args[:remaining] = named_args @args.freeze_named_args!(named_args)
@args.freeze_processed_options!(@processed_options) @args.freeze_processed_options!(@processed_options)
Homebrew.args = @args Homebrew.args = @args
cmdline_args.freeze
@args_parsed = true @args_parsed = true
@parser @parser
end end
@ -186,7 +189,7 @@ module Homebrew
end end
def formula_options def formula_options
@args.formulae.each do |f| formulae.each do |f|
next if f.options.empty? next if f.options.empty?
f.options.each do |o| f.options.each do |o|
@ -341,6 +344,28 @@ module Homebrew
option, = @parser.make_switch(args) option, = @parser.make_switch(args)
@processed_options << [option.short.first, option.long.first, option.arg, option.desc.first] @processed_options << [option.short.first, option.long.first, option.arg, option.desc.first]
end end
def formulae
named_args = @argv.reject { |arg| arg.start_with?("-") }
spec = if @argv.include?("--HEAD")
:head
elsif @argv.include?("--devel")
:devel
else
:stable
end
# Only lowercase names, not paths, bottle filenames or URLs
named_args.map do |arg|
next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX)
if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
Formulary.factory(arg, spec)
else
Formulary.find_with_priority(arg.downcase, spec)
end
end.compact.uniq(&:name)
end
end end
class OptionConstraintError < RuntimeError class OptionConstraintError < RuntimeError

View File

@ -152,7 +152,7 @@ module Homebrew
end end
# --HEAD, fail with no head defined # --HEAD, fail with no head defined
raise "No head is defined for #{f.full_name}" if args.head? && f.head.nil? raise "No head is defined for #{f.full_name}" if args.HEAD? && f.head.nil?
# --devel, fail with no devel defined # --devel, fail with no devel defined
raise "No devel block is defined for #{f.full_name}" if args.devel? && f.devel.nil? raise "No devel block is defined for #{f.full_name}" if args.devel? && f.devel.nil?
@ -325,6 +325,7 @@ module Homebrew
fi.build_bottle = args.build_bottle? fi.build_bottle = args.build_bottle?
fi.interactive = args.interactive? fi.interactive = args.interactive?
fi.git = args.git? fi.git = args.git?
fi.fetch
fi.prelude fi.prelude
fi.install fi.install
fi.finish fi.finish

View File

@ -3,7 +3,7 @@
#: Print export statements. When run in a shell, this installation of Homebrew will be added to your `PATH`, `MANPATH`, and `INFOPATH`. #: Print export statements. When run in a shell, this installation of Homebrew will be added to your `PATH`, `MANPATH`, and `INFOPATH`.
#: #:
#: The variables `HOMEBREW_PREFIX`, `HOMEBREW_CELLAR` and `HOMEBREW_REPOSITORY` are also exported to avoid querying them multiple times. #: The variables `HOMEBREW_PREFIX`, `HOMEBREW_CELLAR` and `HOMEBREW_REPOSITORY` are also exported to avoid querying them multiple times.
#: Consider adding evaluation of this command's output to your dotfiles (e.g. `~/.profile` or `~/.zprofile`) with: `eval $(brew shellenv)` #: Consider adding evaluation of this command's output to your dotfiles (e.g. `~/.profile`, `~/.bash_profile`, or `~/.zprofile`) with: `eval $(brew shellenv)`
homebrew-shellenv() { homebrew-shellenv() {
case "$SHELL" in case "$SHELL" in

View File

@ -12,7 +12,7 @@ module Homebrew
end end
def tap_pin def tap_pin
odisabled "brew tap-pin user/tap", odisabled "the brew tap-pin command",
"fully-scoped user/tap/formula naming" "fully-scoped user/tap/formula naming when installing and in dependency references"
end end
end end

View File

@ -12,7 +12,7 @@ module Homebrew
end end
def tap_unpin def tap_unpin
odisabled "brew tap-pin user/tap", odisabled "the brew tap-unpin command",
"fully-scoped user/tap/formula naming" "fully-scoped user/tap/formula naming when installing and in dependency references"
end end
end end

View File

@ -80,6 +80,30 @@ module Homebrew
puts "#{keg.name} #{versions.to_sentence} #{"is".pluralize(versions.count)} still installed." puts "#{keg.name} #{versions.to_sentence} #{"is".pluralize(versions.count)} still installed."
puts "Run `brew uninstall --force #{keg.name}` to remove all versions." puts "Run `brew uninstall --force #{keg.name}` to remove all versions."
end end
next unless f
paths = f.pkgetc.find.map(&:to_s) if f.pkgetc.exist?
if paths.present?
puts
opoo <<~EOS
The following #{f.name} configuration files have not been removed!
If desired, remove them manually with `rm -rf`:
#{paths.sort.uniq.join("\n ")}
EOS
end
unversioned_name = f.name.gsub(/@.+$/, "")
maybe_paths = Dir.glob("#{f.etc}/*#{unversioned_name}*")
maybe_paths -= paths if paths.present?
if maybe_paths.present?
puts
opoo <<~EOS
The following may be #{f.name} configuration files and have not been removed!
If desired, remove them manually with `rm -rf`:
#{maybe_paths.sort.uniq.join("\n ")}
EOS
end
end end
end end
end end

View File

@ -183,7 +183,6 @@ module Homebrew
fi.installed_as_dependency = tab.installed_as_dependency fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request ||= tab.installed_on_request fi.installed_on_request ||= tab.installed_on_request
end end
fi.prelude
upgrade_version = if f.optlinked? upgrade_version = if f.optlinked?
"#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" "#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
@ -192,6 +191,9 @@ module Homebrew
end end
oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}" oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
fi.fetch
fi.prelude
# first we unlink the currently active keg for this formula otherwise it is # first we unlink the currently active keg for this formula otherwise it is
# possible for the existing build to interfere with the build we are about to # possible for the existing build to interfere with the build we are about to
# do! Seriously, it happens! # do! Seriously, it happens!

View File

@ -4,3 +4,4 @@ require "compat/cask/dsl/version"
require "compat/language/python" require "compat/language/python"
require "compat/requirements/macos_requirement" require "compat/requirements/macos_requirement"
require "compat/formula" require "compat/formula"
require "compat/os/mac" if OS.mac?

View File

@ -0,0 +1,114 @@
# frozen_string_literal: true
module Language
module Haskell
module Cabal
module Compat
def cabal_sandbox(options = {})
# odeprecated "Language::Haskell::Cabal.cabal_sandbox"
pwd = Pathname.pwd
home = options[:home] || pwd
# pretend HOME is elsewhere, so that ~/.cabal is kept as untouched
# as possible (except for ~/.cabal/setup-exe-cache)
# https://github.com/haskell/cabal/issues/1234
saved_home = ENV["HOME"]
ENV["HOME"] = home
system "cabal", "v1-sandbox", "init"
cabal_sandbox_bin = pwd/".cabal-sandbox/bin"
mkdir_p cabal_sandbox_bin
# make available any tools that will be installed in the sandbox
saved_path = ENV["PATH"]
ENV.prepend_path "PATH", cabal_sandbox_bin
# avoid updating the cabal package database more than once
system "cabal", "v1-update" unless (home/".cabal/packages").exist?
yield
# remove the sandbox and all build products
rm_rf [".cabal-sandbox", "cabal.sandbox.config", "dist"]
# avoid installing any Haskell libraries, as a matter of policy
rm_rf lib unless options[:keep_lib]
# restore the environment
ENV["HOME"] = saved_home
ENV["PATH"] = saved_path
end
def cabal_sandbox_add_source(*args)
# odeprecated "Language::Haskell::Cabal.cabal_sandbox_add_source"
system "cabal", "v1-sandbox", "add-source", *args
end
def cabal_install(*args)
# odeprecated "Language::Haskell::Cabal.cabal_install",
# "cabal v2-install directly with std_cabal_v2_args"
# cabal hardcodes 64 as the maximum number of parallel jobs
# https://github.com/Homebrew/legacy-homebrew/issues/49509
make_jobs = (ENV.make_jobs > 64) ? 64 : ENV.make_jobs
# cabal-install's dependency-resolution backtracking strategy can easily
# need more than the default 2,000 maximum number of "backjumps," since
# Hackage is a fast-moving, rolling-release target. The highest known
# needed value by a formula at this time (February 2016) was 43,478 for
# git-annex, so 100,000 should be enough to avoid most gratuitous
# backjumps build failures.
system "cabal", "v1-install", "--jobs=#{make_jobs}", "--max-backjumps=100000", *args
end
def cabal_configure(flags)
# odeprecated "Language::Haskell::Cabal.cabal_configure"
system "cabal", "v1-configure", flags
end
def cabal_install_tools(*tools)
# odeprecated "Language::Haskell::Cabal.cabal_install_tools"
# install tools sequentially, as some tools can depend on other tools
tools.each { |tool| cabal_install tool }
# unregister packages installed as dependencies for the tools, so
# that they can't cause dependency conflicts for the main package
rm_rf Dir[".cabal-sandbox/*packages.conf.d/"]
end
def install_cabal_package(*args, **options)
# odeprecated "Language::Haskell::Cabal.install_cabal_package",
# "cabal v2-update directly followed by v2-install with std_cabal_v2_args"
cabal_sandbox do
cabal_install_tools(*options[:using]) if options[:using]
# if we have build flags, we have to pass them to cabal install to resolve the necessary
# dependencies, and call cabal configure afterwards to set the flags again for compile
flags = "--flags=#{options[:flags].join(" ")}" if options[:flags]
args_and_flags = args
args_and_flags << flags unless flags.nil?
# install dependencies in the sandbox
cabal_install "--only-dependencies", *args_and_flags
# call configure if build flags are set
cabal_configure flags unless flags.nil?
# install the main package in the destination dir
cabal_install "--prefix=#{prefix}", *args
yield if block_given?
end
end
end
prepend Compat
end
end
end

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
module OS
module Mac
class << self
module Compat
def preferred_arch
# odeprecated "MacOS.preferred_arch", "Hardware::CPU.arch (or ideally let the compiler handle it)"
if Hardware::CPU.is_64_bit?
Hardware::CPU.arch_64_bit
else
Hardware::CPU.arch_32_bit
end
end
def tcc_db
# odeprecated "MacOS.tcc_db"
@tcc_db ||= Pathname.new("/Library/Application Support/com.apple.TCC/TCC.db")
end
def pre_mavericks_accessibility_dotfile
# odeprecated "MacOS.pre_mavericks_accessibility_dotfile"
@pre_mavericks_accessibility_dotfile ||= Pathname.new("/private/var/db/.AccessibilityAPIEnabled")
end
end
prepend Compat
end
end
end

View File

@ -106,7 +106,7 @@ class CompilerSelector
def gnu_gcc_versions def gnu_gcc_versions
# prioritize gcc version provided by gcc formula. # prioritize gcc version provided by gcc formula.
v = Formulary.factory("gcc").version.to_s.slice(/\d/) v = Formulary.factory("gcc").version.to_s.slice(/\d+/)
GNU_GCC_VERSIONS - [v] + [v] # move the version to the end of the list GNU_GCC_VERSIONS - [v] + [v] # move the version to the end of the list
rescue FormulaUnavailableError rescue FormulaUnavailableError
GNU_GCC_VERSIONS GNU_GCC_VERSIONS

View File

@ -81,7 +81,7 @@ module Homebrew
ignores << "optional?" ignores << "optional?"
end end
ignores << "recommended?" if ARGV.include? "--skip-recommended" ignores << "recommended?" if Homebrew.args.skip_recommended?
[includes, ignores] [includes, ignores]
end end
@ -100,16 +100,11 @@ module Homebrew
klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep) klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.optional? elsif dep.optional?
klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep) klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.test? elsif dep.build? || dep.test?
if includes.include?("test?") keep = false
Dependency.keep_but_prune_recursive_deps if type == :dependencies keep ||= dep.test? && includes.include?("test?") && dependent == formula
elsif dep.build? keep ||= dep.build? && includes.include?("build?")
klass.prune unless includes.include?("build?") klass.prune unless keep
else
klass.prune
end
elsif dep.build?
klass.prune unless includes.include?("build?")
end end
# If a tap isn't installed, we can't find the dependencies of one of # If a tap isn't installed, we can't find the dependencies of one of

View File

@ -89,9 +89,6 @@ class Dependency
deps.each do |dep| deps.each do |dep|
next if dependent.name == dep.name next if dependent.name == dep.name
# we only care about one level of test dependencies.
next if dep.test? && @expand_stack.length > 1
case action(dependent, dep, &block) case action(dependent, dep, &block)
when :prune when :prune
next next

View File

@ -435,40 +435,6 @@ module Homebrew
end end
end end
def audit_keg_only
return unless formula.keg_only?
whitelist = %w[
Apple
macOS
OS
Homebrew
Xcode
GPG
GNOME
BSD
Firefox
].freeze
reason = formula.keg_only_reason.to_s
# Formulae names can legitimately be uppercase/lowercase/both.
name = Regexp.new(formula.name, Regexp::IGNORECASE)
reason.sub!(name, "")
first_word = reason.split.first
if reason =~ /\A[A-Z]/ && !reason.start_with?(*whitelist)
# TODO: check could be in RuboCop
problem <<~EOS
'#{first_word}' from the keg_only reason should be '#{first_word.downcase}'.
EOS
end
return unless reason.end_with?(".")
# TODO: check could be in RuboCop
problem "keg_only reason should not end with a period."
end
def audit_postgresql def audit_postgresql
return unless formula.name == "postgresql" return unless formula.name == "postgresql"
return unless @core_tap return unless @core_tap
@ -1018,7 +984,7 @@ module Homebrew
except_audits = @except except_audits = @except
methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name| methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name|
name = audit_method_name.gsub(/^audit_/, "") name = audit_method_name.delete_prefix("audit_")
if only_audits if only_audits
next unless only_audits.include?(name) next unless only_audits.include?(name)
elsif except_audits elsif except_audits
@ -1076,9 +1042,6 @@ module Homebrew
def audit_version def audit_version
if version.nil? if version.nil?
problem "missing version" problem "missing version"
elsif version.blank?
# TODO: check could be in RuboCop
problem "version is set to an empty string"
elsif !version.detected_from_url? elsif !version.detected_from_url?
version_text = version version_text = version
version_url = Version.detect(url, specs) version_url = Version.detect(url, specs)
@ -1086,26 +1049,12 @@ module Homebrew
problem "version #{version_text} is redundant with version scanned from URL" problem "version #{version_text} is redundant with version scanned from URL"
end end
end end
# TODO: check could be in RuboCop
problem "version #{version} should not have a leading 'v'" if version.to_s.start_with?("v")
return unless version.to_s.match?(/_\d+$/)
# TODO: check could be in RuboCop
problem "version #{version} should not end with an underline and a number"
end end
def audit_download_strategy def audit_download_strategy
if url =~ %r{^(cvs|bzr|hg|fossil)://} || url =~ %r{^(svn)\+http://}
# TODO: check could be in RuboCop
problem "Use of the #{$&} scheme is deprecated, pass `:using => :#{Regexp.last_match(1)}` instead"
end
url_strategy = DownloadStrategyDetector.detect(url) url_strategy = DownloadStrategyDetector.detect(url)
if using == :git || url_strategy == GitDownloadStrategy if using == :git || url_strategy == GitDownloadStrategy
# TODO: check could be in RuboCop
problem "Git should specify :revision when a :tag is specified." if specs[:tag] && !specs[:revision] problem "Git should specify :revision when a :tag is specified." if specs[:tag] && !specs[:revision]
end end

View File

@ -118,12 +118,6 @@ module Homebrew
formula = args.formulae.first formula = args.formulae.first
if formula
tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula)
check_for_duplicate_pull_requests(formula, tap_full_name)
checked_for_duplicates = true
end
new_url = args.url new_url = args.url
if new_url && !formula if new_url && !formula
# Split the new URL on / and find any formulae that have the same URL # Split the new URL on / and find any formulae that have the same URL
@ -152,7 +146,8 @@ module Homebrew
end end
raise FormulaUnspecifiedError unless formula raise FormulaUnspecifiedError unless formula
check_for_duplicate_pull_requests(formula, tap_full_name) unless checked_for_duplicates tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula)
check_for_duplicate_pull_requests(formula, tap_full_name)
requested_spec, formula_spec = if args.devel? requested_spec, formula_spec = if args.devel?
devel_message = " (devel)" devel_message = " (devel)"

View File

@ -18,7 +18,8 @@ module Homebrew
module_function module_function
def irb_args def irb_args
Homebrew::CLI::Parser.new do # work around IRB modifying ARGV.
Homebrew::CLI::Parser.new(ARGV.dup) do
usage_banner <<~EOS usage_banner <<~EOS
`irb` [<options>] `irb` [<options>]
@ -33,8 +34,7 @@ module Homebrew
end end
def irb def irb
# work around IRB modifying ARGV. irb_args.parse
irb_args.parse(ARGV.dup)
if args.examples? if args.examples?
puts "'v8'.f # => instance of the v8 formula" puts "'v8'.f # => instance of the v8 formula"

View File

@ -41,20 +41,21 @@ module Homebrew
downloader.fetch downloader.fetch
filename = downloader.basename filename = ERB::Util.url_encode(downloader.basename)
destination_url = "https://dl.bintray.com/#{bintray_org}/#{bintray_repo}/#{filename}" destination_url = "https://dl.bintray.com/#{bintray_org}/#{bintray_repo}/#{filename}"
ohai "Uploading to #{destination_url}" ohai "Uploading to #{destination_url}"
version = ERB::Util.url_encode(f.pkg_version)
bintray.upload( bintray.upload(
downloader.cached_location, downloader.cached_location,
repo: bintray_repo, repo: bintray_repo,
package: bintray_package, package: bintray_package,
version: f.pkg_version, version: version,
sha256: f.stable.checksum, sha256: f.stable.checksum,
remote_file: filename, remote_file: filename,
) )
bintray.publish(repo: bintray_repo, package: bintray_package, version: f.pkg_version) bintray.publish(repo: bintray_repo, package: bintray_package, version: version)
ohai "Mirrored #{filename}!" ohai "Mirrored #{filename}!"
end end
end end

View File

@ -16,9 +16,11 @@ module Homebrew
flag "--tap=", flag "--tap=",
description: "Target tap repository (default: `homebrew/core`)." description: "Target tap repository (default: `homebrew/core`)."
flag "--with-label=", flag "--with-label=",
description: "Pull requests must have this label (default: `ready to merge`)." description: "Pull requests must have this label."
comma_array "--without-labels=", comma_array "--without-labels=",
description: "Pull requests must not have these labels (default: `do not merge`, `new formula`)." description: "Pull requests must not have these labels (default: `do not merge`, `new formula`)."
switch "--without-approval",
description: "Pull requests do not require approval to be merged."
switch "--publish", switch "--publish",
description: "Run `brew pr-publish` on matching pull requests." description: "Run `brew pr-publish` on matching pull requests."
switch "--ignore-failures", switch "--ignore-failures",
@ -33,12 +35,13 @@ module Homebrew
pr_automerge_args.parse pr_automerge_args.parse
ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] = "1" unless OS.mac? ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] = "1" unless OS.mac?
with_label = Homebrew.args.with_label || "ready to merge"
without_labels = Homebrew.args.without_labels || ["do not merge", "new formula"] without_labels = Homebrew.args.without_labels || ["do not merge", "new formula"]
tap = Tap.fetch(Homebrew.args.tap || CoreTap.instance.name) tap = Tap.fetch(Homebrew.args.tap || CoreTap.instance.name)
query = "is:pr is:open repo:#{tap.full_name} label:\"#{with_label}\"" query = "is:pr is:open repo:#{tap.full_name}"
query += args.ignore_failures? ? " -status:pending" : " status:success" query += Homebrew.args.ignore_failures? ? " -status:pending" : " status:success"
query += " review:approved" unless Homebrew.args.without_approval?
query += " label:\"#{with_label}\"" if Homebrew.args.with_label
without_labels&.each { |label| query += " -label:\"#{label}\"" } without_labels&.each { |label| query += " -label:\"#{label}\"" }
odebug "Searching: #{query}" odebug "Searching: #{query}"

View File

@ -22,6 +22,8 @@ module Homebrew
switch "--online", switch "--online",
description: "Include tests that use the GitHub API and tests that use any of the taps for "\ description: "Include tests that use the GitHub API and tests that use any of the taps for "\
"official external commands." "official external commands."
switch "--byebug",
description: "Enable debugging using byebug."
flag "--only=", flag "--only=",
description: "Run only <test_script>`_spec.rb`. Appending `:`<line_number> will start at a "\ description: "Run only <test_script>`_spec.rb`. Appending `:`<line_number> will start at a "\
"specific line." "specific line."
@ -39,6 +41,8 @@ module Homebrew
Homebrew.install_bundler_gems! Homebrew.install_bundler_gems!
gem_user_dir = Gem.user_dir gem_user_dir = Gem.user_dir
require "byebug" if args.byebug?
HOMEBREW_LIBRARY_PATH.cd do HOMEBREW_LIBRARY_PATH.cd do
ENV.delete("HOMEBREW_COLOR") ENV.delete("HOMEBREW_COLOR")
ENV.delete("HOMEBREW_NO_COLOR") ENV.delete("HOMEBREW_NO_COLOR")

View File

@ -78,7 +78,7 @@ class DevelopmentTools
path = HOMEBREW_PREFIX/"opt/gcc/bin"/cc path = HOMEBREW_PREFIX/"opt/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

View File

@ -3,6 +3,7 @@
require "keg" require "keg"
require "language/python" require "language/python"
require "formula" require "formula"
require "formulary"
require "version" require "version"
require "development_tools" require "development_tools"
require "utils/shell" require "utils/shell"
@ -832,6 +833,23 @@ module Homebrew
EOS EOS
end end
def check_deleted_formula
kegs = Keg.all
deleted_formulae = []
kegs.each do |keg|
keg_name = keg.name
deleted_formulae << keg_name if Formulary.tap_paths(keg_name).blank?
end
return if deleted_formulae.blank?
message = <<~EOS
Some installed formulae were deleted!
You should find replacements for the following formulae:
#{deleted_formulae.join("\n ")}
EOS
message
end
def all def all
methods.map(&:to_s).grep(/^check_/) methods.map(&:to_s).grep(/^check_/)
end end

View File

@ -23,6 +23,7 @@ class AbstractDownloadStrategy
attr_reader :cache, :cached_location, :url attr_reader :cache, :cached_location, :url
attr_reader :meta, :name, :version, :shutup attr_reader :meta, :name, :version, :shutup
private :meta, :name, :version, :shutup private :meta, :name, :version, :shutup
def initialize(url, name, version, **meta) def initialize(url, name, version, **meta)

View File

@ -11,11 +11,6 @@ module HomebrewArgvExtension
flag?("--debug") || !ENV["HOMEBREW_DEBUG"].nil? flag?("--debug") || !ENV["HOMEBREW_DEBUG"].nil?
end end
def bottle_arch
arch = value "bottle-arch"
arch&.to_sym
end
def env def env
value "env" value "env"
end end

View File

@ -235,20 +235,6 @@ module SharedEnvExtension
ohai "Building with an alternative Fortran compiler" ohai "Building with an alternative Fortran compiler"
puts "This is unsupported." puts "This is unsupported."
self["F77"] ||= fc self["F77"] ||= fc
if ARGV.include? "--default-fortran-flags"
flags = FC_FLAG_VARS.reject { |key| self[key] }
elsif values_at(*FC_FLAG_VARS).compact.empty?
opoo <<~EOS
No Fortran optimization information was provided. You may want to consider
setting FCFLAGS and FFLAGS or pass the `--default-fortran-flags` option to
`brew install` if your compiler is compatible with GCC.
If you like the default optimization level of your compiler, ignore this
warning.
EOS
end
else else
if (gfortran = which("gfortran", (HOMEBREW_PREFIX/"bin").to_s)) if (gfortran = which("gfortran", (HOMEBREW_PREFIX/"bin").to_s))
ohai "Using Homebrew-provided Fortran compiler." ohai "Using Homebrew-provided Fortran compiler."
@ -268,8 +254,8 @@ module SharedEnvExtension
# @private # @private
def effective_arch def effective_arch
if Homebrew.args.build_bottle && ARGV.bottle_arch if Homebrew.args.build_bottle? && Homebrew.args.bottle_arch
ARGV.bottle_arch Homebrew.args.bottle_arch.to_sym
else else
Hardware.oldest_cpu Hardware.oldest_cpu
end end

View File

@ -3,8 +3,10 @@
module SharedEnvExtension module SharedEnvExtension
# @private # @private
def effective_arch def effective_arch
if Homebrew.args.build_bottle? if Homebrew.args.build_bottle? && Homebrew.args.bottle_arch
ARGV.bottle_arch || Hardware.oldest_cpu Homebrew.args.bottle_arch.to_sym
elsif Homebrew.args.build_bottle?
Hardware.oldest_cpu
else else
:native :native
end end

View File

@ -80,7 +80,7 @@ module Hardware
# Compatibility with Mac method, which returns lowercase symbols # Compatibility with Mac method, which returns lowercase symbols
# instead of strings # instead of strings
def features def features
@features ||= flags[1..-1].map(&:intern) @features ||= flags[1..].map(&:intern)
end end
%w[aes altivec avx avx2 lm ssse3 sse4_2].each do |flag| %w[aes altivec avx avx2 lm ssse3 sse4_2].each do |flag|

View File

@ -345,6 +345,18 @@ module Homebrew
directory on the same volume as your Cellar. directory on the same volume as your Cellar.
EOS EOS
end end
def check_deprecated_caskroom_taps
tapped_caskroom_taps = Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" }
.map(&:name)
return if tapped_caskroom_taps.empty?
<<~EOS
You have the following deprecated, cask taps tapped:
#{tapped_caskroom_taps.join("\n ")}
Untap them with `brew untap`.
EOS
end
end end
end end
end end

View File

@ -11,7 +11,7 @@ class SoftwareSpec
deps = Hash[*bounds.shift] deps = Hash[*bounds.shift]
end end
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]
@uses_from_macos_elements << deps @uses_from_macos_elements << deps
else else

View File

@ -5,7 +5,7 @@ module Homebrew
module_function module_function
def fetch_bottle?(f) def fetch_bottle?(f)
return true if Homebrew.args.force_bottle && f.bottle return true if Homebrew.args.force_bottle? && f.bottle
return false unless f.bottle && f.pour_bottle? return false unless f.bottle && f.pour_bottle?
return false if Homebrew.args.build_formula_from_source?(f) return false if Homebrew.args.build_formula_from_source?(f)
return false unless f.bottle.compatible_cellar? return false unless f.bottle.compatible_cellar?

View File

@ -12,6 +12,7 @@ require "build_environment"
require "build_options" require "build_options"
require "formulary" require "formulary"
require "software_spec" require "software_spec"
require "livecheck"
require "install_renamed" require "install_renamed"
require "pkg_version" require "pkg_version"
require "keg" require "keg"
@ -125,6 +126,7 @@ class Formula
# The currently active {SoftwareSpec}. # The currently active {SoftwareSpec}.
# @see #determine_active_spec # @see #determine_active_spec
attr_reader :active_spec attr_reader :active_spec
protected :active_spec protected :active_spec
# A symbol to indicate currently active {SoftwareSpec}. # A symbol to indicate currently active {SoftwareSpec}.
@ -175,6 +177,7 @@ class Formula
# Defaults to true. # Defaults to true.
# @return [Boolean] # @return [Boolean]
attr_accessor :follow_installed_alias attr_accessor :follow_installed_alias
alias follow_installed_alias? follow_installed_alias alias follow_installed_alias? follow_installed_alias
# @private # @private
@ -353,6 +356,16 @@ class Formula
# @see .homepage= # @see .homepage=
delegate homepage: :"self.class" delegate homepage: :"self.class"
# The livecheck specification for the software.
# @method livecheck
# @see .livecheck=
delegate livecheck: :"self.class"
# Is a livecheck specification defined for the software?
# @method livecheckable?
# @see .livecheckable?
delegate livecheckable?: :"self.class"
# The version for the currently active {SoftwareSpec}. # The version for the currently active {SoftwareSpec}.
# The version is autodetected from the URL and/or tag so only needs to be # The version is autodetected from the URL and/or tag so only needs to be
# declared if it cannot be autodetected correctly. # declared if it cannot be autodetected correctly.
@ -790,6 +803,14 @@ class Formula
(HOMEBREW_PREFIX/"etc").extend(InstallRenamed) (HOMEBREW_PREFIX/"etc").extend(InstallRenamed)
end end
# A subdirectory of `etc` with the formula name suffixed.
# e.g. `$HOMEBREW_PREFIX/etc/openssl@1.1`
# Anything using `pkgetc.install` will not overwrite other files on
# e.g. upgrades but will write a new file named `*.default`.
def pkgetc
(HOMEBREW_PREFIX/"etc"/name).extend(InstallRenamed)
end
# The directory where the formula's variable files should be installed. # The directory where the formula's variable files should be installed.
# This directory is not inside the `HOMEBREW_CELLAR` so it persists # This directory is not inside the `HOMEBREW_CELLAR` so it persists
# across upgrades. # across upgrades.
@ -991,11 +1012,11 @@ class Formula
self.build = Tab.for_formula(self) self.build = Tab.for_formula(self)
new_env = { new_env = {
"TMPDIR" => HOMEBREW_TEMP, TMPDIR: HOMEBREW_TEMP,
"TEMP" => HOMEBREW_TEMP, TEMP: HOMEBREW_TEMP,
"TMP" => HOMEBREW_TEMP, TMP: HOMEBREW_TEMP,
"HOMEBREW_PATH" => nil, HOMEBREW_PATH: nil,
"PATH" => ENV["HOMEBREW_PATH"], PATH: ENV["HOMEBREW_PATH"],
} }
with_env(new_env) do with_env(new_env) do
@ -1080,7 +1101,7 @@ class Formula
# keg's formula is deleted. # keg's formula is deleted.
begin begin
keg = Keg.for(path) keg = Keg.for(path)
rescue NotAKegError, Errno::ENOENT # rubocop:disable Lint/SuppressedException rescue NotAKegError, Errno::ENOENT
# file doesn't belong to any keg. # file doesn't belong to any keg.
else else
tab_tap = Tab.for_keg(keg).tap tab_tap = Tab.for_keg(keg).tap
@ -1089,7 +1110,7 @@ class Formula
begin begin
Formulary.factory(keg.name) Formulary.factory(keg.name)
rescue FormulaUnavailableError # rubocop:disable Lint/SuppressedException rescue FormulaUnavailableError
# formula for this keg is deleted, so defer to whitelist # formula for this keg is deleted, so defer to whitelist
rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
return false # this keg belongs to another formula return false # this keg belongs to another formula
@ -1139,11 +1160,14 @@ class Formula
# yields |self,staging| with current working directory set to the uncompressed tarball # yields |self,staging| with current working directory set to the uncompressed tarball
# where staging is a Mktemp staging context # where staging is a Mktemp staging context
# @private # @private
def brew def brew(fetch: true)
@prefix_returns_versioned_prefix = true @prefix_returns_versioned_prefix = true
active_spec.fetch if fetch
stage do |staging| stage do |staging|
staging.retain! if Homebrew.args.keep_tmp? staging.retain! if Homebrew.args.keep_tmp?
prepare_patches prepare_patches
fetch_patches if fetch
begin begin
yield self, staging yield self, staging
@ -1203,7 +1227,7 @@ class Formula
next if version.head? next if version.head?
tab = Tab.for_keg(keg) tab = Tab.for_keg(keg)
next if version_scheme > tab.version_scheme next if version_scheme > tab.version_scheme && pkg_version != version
next if version_scheme == tab.version_scheme && pkg_version > version next if version_scheme == tab.version_scheme && pkg_version > version
# don't consider this keg current if there's a newer formula available # don't consider this keg current if there's a newer formula available
@ -1694,6 +1718,13 @@ class Formula
%w[stable devel].each do |spec_sym| %w[stable devel].each do |spec_sym|
next unless spec = send(spec_sym) next unless spec = send(spec_sym)
hsh["urls"][spec_sym] = {
"url" => spec.url,
"tag" => spec.specs[:tag],
"revision" => spec.specs[:revision],
}
next unless spec.bottle_defined? next unless spec.bottle_defined?
bottle_spec = spec.bottle_specification bottle_spec = spec.bottle_specification
@ -1713,11 +1744,6 @@ class Formula
} }
end end
hsh["bottle"][spec_sym] = bottle_info hsh["bottle"][spec_sym] = bottle_info
hsh["urls"][spec_sym] = {
"url" => spec.url,
"tag" => spec.specs[:tag],
"revision" => spec.specs[:revision],
}
end end
hsh["options"] = options.map do |opt| hsh["options"] = options.map do |opt|
@ -2057,8 +2083,17 @@ class Formula
ENV.update(removed) ENV.update(removed)
end end
def fetch_patches
patchlist.select(&:external?).each(&:fetch)
end
private private
def prepare_patches
active_spec.add_legacy_patches(patches) if respond_to?(:patches)
patchlist.grep(DATAPatch) { |p| p.path = path }
end
# Returns the prefix for a given formula version number. # Returns the prefix for a given formula version number.
# @private # @private
def versioned_prefix(v) def versioned_prefix(v)
@ -2126,13 +2161,6 @@ class Formula
end end
end end
def prepare_patches
active_spec.add_legacy_patches(patches) if respond_to?(:patches)
patchlist.grep(DATAPatch) { |p| p.path = path }
patchlist.select(&:external?).each(&:fetch)
end
# The methods below define the formula DSL. # The methods below define the formula DSL.
class << self class << self
include BuildEnvironment::DSL include BuildEnvironment::DSL
@ -2178,6 +2206,13 @@ class Formula
# <pre>homepage "https://www.example.com"</pre> # <pre>homepage "https://www.example.com"</pre>
attr_rw :homepage attr_rw :homepage
# Whether a livecheck specification is defined or not.
# It returns true when a livecheck block is present in the {Formula} and
# false otherwise, and is used by livecheck.
def livecheckable?
@livecheckable == true
end
# The `:startup` attribute set by {.plist_options}. # The `:startup` attribute set by {.plist_options}.
# @private # @private
attr_reader :plist_startup attr_reader :plist_startup
@ -2620,6 +2655,26 @@ class Formula
define_method(:test, &block) define_method(:test, &block)
end end
# @!attribute [w] livecheck
# Livecheck can be used to check for newer versions of the software.
# This method evaluates the DSL specified in the livecheck block of the
# {Formula} (if it exists) and sets the instance variables of a Livecheck
# object accordingly. This is used by brew livecheck to check for newer
# versions of the software.
#
# <pre>livecheck do
# skip "Not maintained"
# url "https://example.com/foo/releases"
# regex /foo-(\d+(?:\.\d+)+)\.tar/
# end</pre>
def livecheck(&block)
@livecheck ||= Livecheck.new
return @livecheck unless block_given?
@livecheckable = true
@livecheck.instance_eval(&block)
end
# Defines whether the {Formula}'s bottle can be used on the given Homebrew # Defines whether the {Formula}'s bottle can be used on the given Homebrew
# installation. # installation.
# #

View File

@ -224,6 +224,41 @@ module FormulaCellarChecks
EOS EOS
end end
def check_plist(prefix, plist)
return unless prefix.directory?
plist = begin
Plist.parse_xml(plist)
rescue
nil
end
return if plist.blank?
program_location = plist["ProgramArguments"]&.first
key = "first ProgramArguments value"
if program_location.blank?
program_location = plist["Program"]
key = "Program"
end
return if program_location.blank?
Dir.chdir("/") do
unless File.exist?(program_location)
return <<~EOS
The plist #{key} does not exist:
#{program_location}
EOS
end
return if File.executable?(program_location)
end
<<~EOS
The plist #{key} is not executable:
#{program_location}
EOS
end
def audit_installed def audit_installed
@new_formula ||= false @new_formula ||= false
@ -240,6 +275,7 @@ module FormulaCellarChecks
problem_if_output(check_elisp_root(formula.share, formula.name)) problem_if_output(check_elisp_root(formula.share, formula.name))
problem_if_output(check_python_packages(formula.lib, formula.deps)) problem_if_output(check_python_packages(formula.lib, formula.deps))
problem_if_output(check_shim_references(formula.prefix)) problem_if_output(check_shim_references(formula.prefix))
problem_if_output(check_plist(formula.prefix, formula.plist))
end end
alias generic_audit_installed audit_installed alias generic_audit_installed audit_installed

View File

@ -25,6 +25,7 @@ class FormulaInstaller
def self.mode_attr_accessor(*names) def self.mode_attr_accessor(*names)
attr_accessor(*names) attr_accessor(*names)
private(*names) private(*names)
names.each do |name| names.each do |name|
predicate = "#{name}?" predicate = "#{name}?"
@ -38,6 +39,7 @@ class FormulaInstaller
attr_reader :formula attr_reader :formula
attr_accessor :options, :build_bottle attr_accessor :options, :build_bottle
attr_accessor :installed_as_dependency, :installed_on_request, :link_keg attr_accessor :installed_as_dependency, :installed_on_request, :link_keg
mode_attr_accessor :show_summary_heading, :show_header mode_attr_accessor :show_summary_heading, :show_header
mode_attr_accessor :build_from_source, :force_bottle, :include_test mode_attr_accessor :build_from_source, :force_bottle, :include_test
mode_attr_accessor :ignore_deps, :only_deps, :interactive, :git mode_attr_accessor :ignore_deps, :only_deps, :interactive, :git
@ -49,10 +51,10 @@ class FormulaInstaller
@show_header = false @show_header = false
@ignore_deps = false @ignore_deps = false
@only_deps = false @only_deps = false
@build_from_source = Homebrew.args.build_from_source @build_from_source = Homebrew.args.build_from_source?
@build_bottle = false @build_bottle = false
@force_bottle = Homebrew.args.force_bottle @force_bottle = Homebrew.args.force_bottle?
@include_test = ARGV.include?("--include-test") @include_test = Homebrew.args.include_test?
@interactive = false @interactive = false
@git = false @git = false
@verbose = Homebrew.args.verbose? @verbose = Homebrew.args.verbose?
@ -267,7 +269,7 @@ class FormulaInstaller
return if only_deps? return if only_deps?
if build_bottle? && (arch = ARGV.bottle_arch) && !Hardware::CPU.optimization_flags.include?(arch) if build_bottle? && (arch = Homebrew.args.bottle_arch) && !Hardware::CPU.optimization_flags.include?(arch.to_sym)
raise "Unrecognized architecture for --bottle-arch: #{arch}" raise "Unrecognized architecture for --bottle-arch: #{arch}"
end end
@ -277,7 +279,7 @@ class FormulaInstaller
opoo "#{formula.full_name}: #{old_flag} was deprecated; using #{new_flag} instead!" opoo "#{formula.full_name}: #{old_flag} was deprecated; using #{new_flag} instead!"
end end
options = display_options(formula) options = display_options(formula).join(" ")
oh1 "Installing #{Formatter.identifier(formula.full_name)} #{options}".strip if show_header? oh1 "Installing #{Formatter.identifier(formula.full_name)} #{options}".strip if show_header?
unless formula.tap&.private? unless formula.tap&.private?
@ -451,13 +453,16 @@ class FormulaInstaller
build = effective_build_options_for(dependent) build = effective_build_options_for(dependent)
install_bottle_for_dependent = install_bottle_for?(dependent, build) install_bottle_for_dependent = install_bottle_for?(dependent, build)
keep_build_test = false
keep_build_test ||= runtime_requirements.include?(req)
keep_build_test ||= req.test? && include_test? && dependent == f
keep_build_test ||= req.build? && !install_bottle_for_dependent && !dependent.latest_version_installed?
if req.prune_from_option?(build) if req.prune_from_option?(build)
Requirement.prune Requirement.prune
elsif req.satisfied? elsif req.satisfied?
Requirement.prune Requirement.prune
elsif include_test? && req.test? elsif (req.build? || req.test?) && !keep_build_test
next
elsif !runtime_requirements.include?(req) && install_bottle_for_dependent
Requirement.prune Requirement.prune
elsif (dep = formula_deps_map[dependent.name]) && dep.build? elsif (dep = formula_deps_map[dependent.name]) && dep.build?
Requirement.prune Requirement.prune
@ -484,13 +489,13 @@ class FormulaInstaller
inherited_options.fetch(dependent.name, []), inherited_options.fetch(dependent.name, []),
) )
keep_build_test = false
keep_build_test ||= dep.test? && include_test? && Homebrew.args.include_formula_test_deps?(dependent)
keep_build_test ||= dep.build? && !install_bottle_for?(dependent, build) && !dependent.latest_version_installed?
if dep.prune_from_option?(build) if dep.prune_from_option?(build)
Dependency.prune Dependency.prune
elsif include_test? && dep.test? && !dep.installed? elsif (dep.build? || dep.test?) && !keep_build_test
Dependency.keep_but_prune_recursive_deps
elsif dep.build? && install_bottle_for?(dependent, build)
Dependency.prune
elsif dep.prune_if_build_and_not_dependent?(dependent)
Dependency.prune Dependency.prune
elsif dep.satisfied?(inherited_options[dep.name]) elsif dep.satisfied?(inherited_options[dep.name])
Dependency.skip Dependency.skip
@ -527,16 +532,15 @@ class FormulaInstaller
end end
def display_options(formula) def display_options(formula)
options = [] options = if formula.head?
if formula.head? ["--HEAD"]
options << "--HEAD"
elsif formula.devel? elsif formula.devel?
options << "--devel" ["--devel"]
else
[]
end end
options += effective_build_options_for(formula).used_options.to_a options += effective_build_options_for(formula).used_options.to_a
return if options.empty? options
options.join(" ")
end end
def inherited_options_for(dep) def inherited_options_for(dep)
@ -561,6 +565,23 @@ class FormulaInstaller
@show_header = true unless deps.empty? @show_header = true unless deps.empty?
end end
def fetch_dependency(dep)
df = dep.to_formula
fi = FormulaInstaller.new(df)
fi.build_from_source = Homebrew.args.build_formula_from_source?(df)
fi.force_bottle = false
fi.include_test = Homebrew.args.include_formula_test_deps?(df)
fi.verbose = verbose?
fi.quiet = quiet?
fi.debug = debug?
# When fetching we don't need to recurse the dependency tree as it's already
# been done for us in `compute_dependencies` and there's no requirement to
# fetch in a particular order.
fi.ignore_deps = true
fi.fetch
end
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) tab = Tab.for_formula(df)
@ -593,6 +614,7 @@ class FormulaInstaller
fi.options &= df.options fi.options &= df.options
fi.build_from_source = Homebrew.args.build_formula_from_source?(df) fi.build_from_source = Homebrew.args.build_formula_from_source?(df)
fi.force_bottle = false fi.force_bottle = false
fi.include_test = Homebrew.args.include_formula_test_deps?(df)
fi.verbose = verbose? fi.verbose = verbose?
fi.quiet = quiet? fi.quiet = quiet?
fi.debug = debug? fi.debug = debug?
@ -699,7 +721,7 @@ class FormulaInstaller
if build_bottle? if build_bottle?
args << "--build-bottle" args << "--build-bottle"
args << "--bottle-arch=#{ARGV.bottle_arch}" if ARGV.bottle_arch args << "--bottle-arch=#{Homebrew.args.bottle_arch}" if Homebrew.args.bottle_arch
end end
args << "--git" if git? args << "--git" if git?
@ -707,7 +729,6 @@ class FormulaInstaller
args << "--verbose" if verbose? args << "--verbose" if verbose?
args << "--debug" if debug? args << "--debug" if debug?
args << "--cc=#{Homebrew.args.cc}" if Homebrew.args.cc args << "--cc=#{Homebrew.args.cc}" if Homebrew.args.cc
args << "--default-fortran-flags" if ARGV.include? "--default-fortran-flags"
args << "--keep-tmp" if Homebrew.args.keep_tmp? args << "--keep-tmp" if Homebrew.args.keep_tmp?
if ARGV.env if ARGV.env
@ -776,7 +797,7 @@ class FormulaInstaller
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
if e.is_a? BuildError if e.is_a? BuildError
e.formula = formula e.formula = formula
e.options = options e.options = display_options(formula)
end end
ignore_interrupts do ignore_interrupts do
@ -947,14 +968,38 @@ class FormulaInstaller
@show_summary_heading = true @show_summary_heading = true
end end
def pour def fetch_dependencies
if (bottle_path = formula.local_bottle_path) deps = compute_dependencies
downloader = LocalBottleDownloadStrategy.new(bottle_path)
else return if deps.empty? || ignore_deps?
downloader = formula.bottle
downloader.fetch deps.each { |dep, _options| fetch_dependency(dep) }
end
def fetch
fetch_dependencies
return if only_deps?
unless pour_bottle?
formula.fetch_patches
formula.resources.each(&:fetch)
end end
downloader.fetch
end
def downloader
if (bottle_path = formula.local_bottle_path)
LocalBottleDownloadStrategy.new(bottle_path)
elsif pour_bottle?
formula.bottle
else
formula
end
end
def pour
HOMEBREW_CELLAR.cd do HOMEBREW_CELLAR.cd do
downloader.stage downloader.stage
end end

View File

@ -491,8 +491,8 @@ module Formulary
if possible_pinned_tap_formulae.size == 1 if possible_pinned_tap_formulae.size == 1
selected_formula = factory(possible_pinned_tap_formulae.first, spec) selected_formula = factory(possible_pinned_tap_formulae.first, spec)
if core_path(ref).file? if core_path(ref).file?
odisabled "brew tap-pin user/tap", odisabled "the brew tap-pin command",
"fully-scoped user/tap/formula naming" "fully-scoped user/tap/formula naming when installing and in dependency references"
end end
selected_formula selected_formula
else else

View File

@ -85,7 +85,7 @@ module Homebrew
end end
def args def args
@args ||= CLI::Args.new @args ||= CLI::Args.new(set_default_args: true)
end end
def messages def messages

View File

@ -103,7 +103,7 @@ module Homebrew
help_lines = command_help_lines(path) help_lines = command_help_lines(path)
return if help_lines.blank? return if help_lines.blank?
Formatter.wrap(help_lines.join.gsub(/^ /, ""), COMMAND_DESC_WIDTH) Formatter.wrap(help_lines.join.delete_prefix(" "), COMMAND_DESC_WIDTH)
.sub("@hide_from_man_page ", "") .sub("@hide_from_man_page ", "")
.sub(/^\* /, "#{Tty.bold}Usage: brew#{Tty.reset} ") .sub(/^\* /, "#{Tty.bold}Usage: brew#{Tty.reset} ")
.gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}") .gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}")

View File

@ -184,6 +184,7 @@ class Keg
end end
attr_reader :path, :name, :linked_keg_record, :opt_record attr_reader :path, :name, :linked_keg_record, :opt_record
protected :path protected :path
extend Forwardable extend Forwardable

View File

@ -1,96 +1,3 @@
# frozen_string_literal: true # frozen_string_literal: true
module Language require "compat/language/haskell"
module Haskell
module Cabal
def cabal_sandbox(options = {})
pwd = Pathname.pwd
home = options[:home] || pwd
# pretend HOME is elsewhere, so that ~/.cabal is kept as untouched
# as possible (except for ~/.cabal/setup-exe-cache)
# https://github.com/haskell/cabal/issues/1234
saved_home = ENV["HOME"]
ENV["HOME"] = home
system "cabal", "v1-sandbox", "init"
cabal_sandbox_bin = pwd/".cabal-sandbox/bin"
mkdir_p cabal_sandbox_bin
# make available any tools that will be installed in the sandbox
saved_path = ENV["PATH"]
ENV.prepend_path "PATH", cabal_sandbox_bin
# avoid updating the cabal package database more than once
system "cabal", "v1-update" unless (home/".cabal/packages").exist?
yield
# remove the sandbox and all build products
rm_rf [".cabal-sandbox", "cabal.sandbox.config", "dist"]
# avoid installing any Haskell libraries, as a matter of policy
rm_rf lib unless options[:keep_lib]
# restore the environment
ENV["HOME"] = saved_home
ENV["PATH"] = saved_path
end
def cabal_sandbox_add_source(*args)
system "cabal", "v1-sandbox", "add-source", *args
end
def cabal_install(*args)
# cabal hardcodes 64 as the maximum number of parallel jobs
# https://github.com/Homebrew/legacy-homebrew/issues/49509
make_jobs = (ENV.make_jobs > 64) ? 64 : ENV.make_jobs
# cabal-install's dependency-resolution backtracking strategy can easily
# need more than the default 2,000 maximum number of "backjumps," since
# Hackage is a fast-moving, rolling-release target. The highest known
# needed value by a formula at this time (February 2016) was 43,478 for
# git-annex, so 100,000 should be enough to avoid most gratuitous
# backjumps build failures.
system "cabal", "v1-install", "--jobs=#{make_jobs}", "--max-backjumps=100000", *args
end
def cabal_configure(flags)
system "cabal", "v1-configure", flags
end
def cabal_install_tools(*tools)
# install tools sequentially, as some tools can depend on other tools
tools.each { |tool| cabal_install tool }
# unregister packages installed as dependencies for the tools, so
# that they can't cause dependency conflicts for the main package
rm_rf Dir[".cabal-sandbox/*packages.conf.d/"]
end
def install_cabal_package(*args, **options)
cabal_sandbox do
cabal_install_tools(*options[:using]) if options[:using]
# if we have build flags, we have to pass them to cabal install to resolve the necessary
# dependencies, and call cabal configure afterwards to set the flags again for compile
flags = "--flags=#{options[:flags].join(" ")}" if options[:flags]
args_and_flags = args
args_and_flags << flags unless flags.nil?
# install dependencies in the sandbox
cabal_install "--only-dependencies", *args_and_flags
# call configure if build flags are set
cabal_configure flags unless flags.nil?
# install the main package in the destination dir
cabal_install "--prefix=#{prefix}", *args
yield if block_given?
end
end
end
end
end

View File

@ -0,0 +1,59 @@
# frozen_string_literal: true
# Livecheck can be used to check for newer versions of the software.
# The livecheck DSL specified in the formula is evaluated the methods
# of this class, which set the instance variables accordingly. The
# information is used by brew livecheck when checking for newer versions
# of the software.
class Livecheck
# The reason for skipping livecheck for the formula.
# e.g. `Not maintained`
attr_reader :skip_msg
def initialize
@regex = nil
@skip = false
@skip_msg = nil
@url = nil
end
# Sets the regex instance variable to the argument given, returns the
# regex instance variable when no argument is given.
def regex(pattern = nil)
return @regex if pattern.nil?
@regex = pattern
end
# Sets the skip instance variable to true, indicating that livecheck
# must be skipped for the formula. If an argument is given and present,
# its value is assigned to the skip_msg instance variable, else nil is
# assigned.
def skip(skip_msg = nil)
@skip = true
@skip_msg = skip_msg.presence
end
# Should livecheck be skipped for the formula?
def skip?
@skip
end
# Sets the url instance variable to the argument given, returns the url
# instance variable when no argument is given.
def url(val = nil)
return @url if val.nil?
@url = val
end
# Returns a Hash of all instance variable values.
def to_hash
{
"regex" => @regex,
"skip" => @skip,
"skip_msg" => @skip_msg,
"url" => @url,
}
end
end

View File

@ -243,7 +243,8 @@ Environment variables specific to Homebrew Cask:
* `HOMEBREW_CASK_OPTS`: * `HOMEBREW_CASK_OPTS`:
This variable may contain any arguments normally used as options on This variable may contain any arguments normally used as options on
the command-line. This is particularly useful to make options persistent. the command-line. This is particularly useful to make options persistent.
For example, you might add to your .bash_profile or .zshenv something like: For example, you might add to your ~/.profile, ~/.bash_profile, or ~/.zshenv
something like:
export HOMEBREW_CASK_OPTS='--appdir=~/Applications --fontdir=/Library/Fonts' export HOMEBREW_CASK_OPTS='--appdir=~/Applications --fontdir=/Library/Fonts'

View File

@ -132,6 +132,8 @@ module ELFShim
elsif DevelopmentTools.locate "patchelf" elsif DevelopmentTools.locate "patchelf"
needed_libraries_using_patchelf path needed_libraries_using_patchelf path
else else
return [nil, []] if path.basename.to_s == "patchelf"
raise "patchelf must be installed: brew install patchelf" raise "patchelf must be installed: brew install patchelf"
end end
end end

View File

@ -15,7 +15,7 @@ module OS
end end
def minimum_version def minimum_version
Version.new "2.12" Version.new "2.13"
end end
def below_minimum_version? def below_minimum_version?

View File

@ -166,14 +166,6 @@ module OS
paths.uniq paths.uniq
end end
def preferred_arch
if Hardware::CPU.is_64_bit?
Hardware::CPU.arch_64_bit
else
Hardware::CPU.arch_32_bit
end
end
def app_with_bundle_id(*ids) def app_with_bundle_id(*ids)
path = mdfind(*ids) path = mdfind(*ids)
.reject { |p| p.include?("/Backups.backupdb/") } .reject { |p| p.include?("/Backups.backupdb/") }
@ -196,13 +188,5 @@ module OS
def mdfind_query(*ids) def mdfind_query(*ids)
ids.map! { |id| "kMDItemCFBundleIdentifier == #{id}" }.join(" || ") ids.map! { |id| "kMDItemCFBundleIdentifier == #{id}" }.join(" || ")
end end
def tcc_db
@tcc_db ||= Pathname.new("/Library/Application Support/com.apple.TCC/TCC.db")
end
def pre_mavericks_accessibility_dotfile
@pre_mavericks_accessibility_dotfile ||= Pathname.new("/private/var/db/.AccessibilityAPIEnabled")
end
end end
end end

View File

@ -117,8 +117,8 @@ class ExternalPatch
attr_reader :resource, :strip attr_reader :resource, :strip
def_delegators :resource, def_delegators :resource,
:url, :fetch, :patch_files, :verify_download_integrity, :cached_download, :url, :fetch, :patch_files, :verify_download_integrity,
:clear_cache :cached_download, :downloaded?, :clear_cache
def initialize(strip, &block) def initialize(strip, &block)
@strip = strip @strip = strip

View File

@ -25,7 +25,7 @@ module Homebrew
fi = FormulaInstaller.new(f) fi = FormulaInstaller.new(f)
fi.options = options fi.options = options
fi.build_bottle = Homebrew.args.build_bottle fi.build_bottle = Homebrew.args.build_bottle?
fi.interactive = Homebrew.args.interactive? fi.interactive = Homebrew.args.interactive?
fi.git = Homebrew.args.git? fi.git = Homebrew.args.git?
fi.link_keg ||= keg_was_linked if keg_had_linked_opt fi.link_keg ||= keg_was_linked if keg_had_linked_opt
@ -35,6 +35,7 @@ module Homebrew
fi.installed_as_dependency = tab.installed_as_dependency fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request = tab.installed_on_request fi.installed_on_request = tab.installed_on_request
end end
fi.fetch
fi.prelude fi.prelude
oh1 "Reinstalling #{Formatter.identifier(f.full_name)} #{options.to_a.join " "}" oh1 "Reinstalling #{Formatter.identifier(f.full_name)} #{options.to_a.join " "}"

View File

@ -151,6 +151,7 @@ class Requirement
include BuildEnvironment::DSL include BuildEnvironment::DSL
attr_reader :env_proc, :build attr_reader :env_proc, :build
attr_rw :fatal, :cask, :download attr_rw :fatal, :cask, :download
def satisfy(options = nil, &block) def satisfy(options = nil, &block)

View File

@ -55,6 +55,10 @@ class Resource
"#{owner.name}--#{escaped_name}" "#{owner.name}--#{escaped_name}"
end end
def downloaded?
cached_download.exist?
end
def cached_download def cached_download
downloader.cached_location downloader.cached_location
end end
@ -68,16 +72,23 @@ class Resource
# directory. Subclasses that override stage should implement the tmp # directory. Subclasses that override stage should implement the tmp
# dir using {Mktemp} so that works with all subtypes. # dir using {Mktemp} so that works with all subtypes.
def stage(target = nil, &block) def stage(target = nil, &block)
raise ArgumentError, "target directory or block is required" unless target || block raise ArgumentError, "target directory or block is required" if target.blank? && block.blank?
fetch
prepare_patches prepare_patches
fetch_patches(skip_downloaded: true)
fetch unless downloaded?
unpack(target, &block) unpack(target, &block)
end end
def prepare_patches def prepare_patches
patches.grep(DATAPatch) { |p| p.path = owner.owner.path } patches.grep(DATAPatch) { |p| p.path = owner.owner.path }
patches.select(&:external?).each(&:fetch) end
def fetch_patches(skip_downloaded: false)
external_patches = patches.select(&:external?)
external_patches.reject!(&:downloaded?) if skip_downloaded
external_patches.each(&:fetch)
end end
def apply_patches def apply_patches
@ -114,6 +125,8 @@ class Resource
def fetch(verify_download_integrity: true) def fetch(verify_download_integrity: true)
HOMEBREW_CACHE.mkpath HOMEBREW_CACHE.mkpath
fetch_patches
begin begin
downloader.fetch downloader.fetch
rescue ErrorDuringExecution, CurlDownloadStrategyError => e rescue ErrorDuringExecution, CurlDownloadStrategyError => e

View File

@ -20,5 +20,7 @@ require "rubocops/lines"
require "rubocops/class" require "rubocops/class"
require "rubocops/uses_from_macos" require "rubocops/uses_from_macos"
require "rubocops/files" require "rubocops/files"
require "rubocops/keg_only"
require "rubocops/version"
require "rubocops/rubocop-cask" require "rubocops/rubocop-cask"

View File

@ -40,6 +40,7 @@ module RuboCop
private private
attr_reader :cask_block attr_reader :cask_block
def_delegators :cask_block, :cask_node, :toplevel_stanzas, def_delegators :cask_block, :cask_node, :toplevel_stanzas,
:sorted_toplevel_stanzas :sorted_toplevel_stanzas
@ -141,10 +142,10 @@ module RuboCop
end end
home = homepage.downcase home = homepage.downcase
if (split_host = host.split(".")).length >= 3 if (split_host = host.split(".")).length >= 3
host = split_host[-2..-1].join(".") host = split_host[-2..].join(".")
end end
if (split_home = homepage.split(".")).length >= 3 if (split_home = homepage.split(".")).length >= 3
home = split_home[-2..-1].join(".") home = split_home[-2..].join(".")
end end
host == home host == home
end end

View File

@ -19,6 +19,7 @@ module RuboCop
private private
attr_reader :cask_block attr_reader :cask_block
def_delegators :cask_block, def_delegators :cask_block,
:toplevel_stanzas :toplevel_stanzas
end end

View File

@ -39,6 +39,7 @@ module RuboCop
private private
attr_reader :cask_block, :line_ops attr_reader :cask_block, :line_ops
def_delegators :cask_block, :cask_node, :toplevel_stanzas def_delegators :cask_block, :cask_node, :toplevel_stanzas
def add_offenses def add_offenses

View File

@ -31,6 +31,7 @@ module RuboCop
private private
attr_reader :cask_block attr_reader :cask_block
def_delegators :cask_block, :cask_node, :toplevel_stanzas, def_delegators :cask_block, :cask_node, :toplevel_stanzas,
:sorted_toplevel_stanzas :sorted_toplevel_stanzas

View File

@ -12,24 +12,25 @@ module RuboCop
class ComponentsOrder < FormulaCop class ComponentsOrder < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node) def audit_formula(_node, _class_node, _parent_class_node, body_node)
component_precedence_list = [ component_precedence_list = [
[{ name: :include, type: :method_call }], [{ name: :include, type: :method_call }],
[{ name: :desc, type: :method_call }], [{ name: :desc, type: :method_call }],
[{ name: :homepage, type: :method_call }], [{ name: :homepage, type: :method_call }],
[{ name: :url, type: :method_call }], [{ name: :url, type: :method_call }],
[{ name: :mirror, type: :method_call }], [{ name: :mirror, type: :method_call }],
[{ name: :version, type: :method_call }], [{ name: :version, type: :method_call }],
[{ name: :sha256, type: :method_call }], [{ name: :sha256, type: :method_call }],
[{ name: :revision, type: :method_call }], [{ name: :revision, type: :method_call }],
[{ name: :version_scheme, type: :method_call }], [{ name: :version_scheme, type: :method_call }],
[{ name: :head, type: :method_call }], [{ name: :head, type: :method_call }],
[{ name: :stable, type: :block_call }], [{ name: :stable, type: :block_call }],
[{ name: :bottle, type: :block_call }], [{ name: :livecheck, type: :block_call }],
[{ name: :bottle, type: :block_call }],
[{ name: :pour_bottle?, type: :block_call }], [{ name: :pour_bottle?, type: :block_call }],
[{ name: :devel, type: :block_call }], [{ name: :devel, type: :block_call }],
[{ name: :head, type: :block_call }], [{ name: :head, type: :block_call }],
[{ name: :bottle, type: :method_call }], [{ name: :bottle, type: :method_call }],
[{ name: :keg_only, type: :method_call }], [{ name: :keg_only, type: :method_call }],
[{ name: :option, type: :method_call }], [{ name: :option, type: :method_call }],
[{ name: :deprecated_option, type: :method_call }], [{ name: :deprecated_option, type: :method_call }],
[{ name: :depends_on, type: :method_call }], [{ name: :depends_on, type: :method_call }],
[{ name: :uses_from_macos, type: :method_call }], [{ name: :uses_from_macos, type: :method_call }],

View File

@ -17,6 +17,7 @@ module RuboCop
include RangeHelp include RangeHelp
attr_accessor :file_path attr_accessor :file_path
@registry = Cop.registry @registry = Cop.registry
# This method is called by RuboCop and is the main entry point # This method is called by RuboCop and is the main entry point

View File

@ -0,0 +1,41 @@
# frozen_string_literal: true
require "rubocops/extend/formula"
module RuboCop
module Cop
module FormulaAudit
class KegOnly < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
keg_only_node = find_node_method_by_name(body_node, :keg_only)
return unless keg_only_node
whitelist = %w[
Apple
macOS
OS
Homebrew
Xcode
GPG
GNOME
BSD
Firefox
].freeze
reason = string_content(parameters(keg_only_node).first)
name = Regexp.new(@formula_name, Regexp::IGNORECASE)
reason = reason.sub(name, "")
first_word = reason.split.first
if reason =~ /\A[A-Z]/ && !reason.start_with?(*whitelist)
problem "'#{first_word}' from the keg_only reason should be '#{first_word.downcase}'."
end
return unless reason.end_with?(".")
problem "keg_only reason should not end with a period."
end
end
end
end
end

View File

@ -66,6 +66,16 @@ module RuboCop
problem "#{url} should be `https://www.apache.org/dyn/closer.lua?path=#{match[1]}`" problem "#{url} should be `https://www.apache.org/dyn/closer.lua?path=#{match[1]}`"
end end
version_control_pattern = %r{^(cvs|bzr|hg|fossil)://}
audit_urls(urls, version_control_pattern) do |match, _|
problem "Use of the #{match[1]}:// scheme is deprecated, pass `:using => :#{match[1]}` instead"
end
svn_pattern = %r{^svn\+http://}
audit_urls(urls, svn_pattern) do |_, _|
problem "Use of the svn+http:// scheme is deprecated, pass `:using => :svn` instead"
end
audit_urls(mirrors, /.*/) do |_, mirror| audit_urls(mirrors, /.*/) do |_, mirror|
urls.each do |url| urls.each do |url|
url_string = string_content(parameters(url).first) url_string = string_content(parameters(url).first)
@ -220,7 +230,7 @@ module RuboCop
# Use new-style archive downloads # Use new-style archive downloads
archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/} archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/}
audit_urls(urls, archive_gh_pattern) do |_, url| audit_urls(urls, archive_gh_pattern) do |_, url|
next if url.match?(/\.git$/) next if url.end_with?(".git")
problem "Use /archive/ URLs for GitHub tarballs (url is #{url})." problem "Use /archive/ URLs for GitHub tarballs (url is #{url})."
end end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
require "rubocops/extend/formula"
module RuboCop
module Cop
module FormulaAudit
class Version < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
version_node = find_node_method_by_name(body_node, :version)
return unless version_node
version = string_content(parameters(version_node).first)
problem "version is set to an empty string" if version.empty?
problem "version #{version} should not have a leading 'v'" if version.start_with?("v")
return unless version.match?(/_\d+$/)
problem "version #{version} should not end with an underline and a number"
end
end
end
end
end

View File

@ -11,7 +11,6 @@ require "patch"
require "compilers" require "compilers"
require "global" require "global"
require "os/mac/version" require "os/mac/version"
require "cli/parser"
class SoftwareSpec class SoftwareSpec
extend Forwardable extend Forwardable
@ -96,7 +95,7 @@ class SoftwareSpec
def bottled? def bottled?
bottle_specification.tag?(Utils::Bottles.tag) && \ bottle_specification.tag?(Utils::Bottles.tag) && \
(bottle_specification.compatible_cellar? || Homebrew.args.force_bottle) (bottle_specification.compatible_cellar? || Homebrew.args.force_bottle?)
end end
def bottle(disable_type = nil, disable_reason = nil, &block) def bottle(disable_type = nil, disable_reason = nil, &block)
@ -275,7 +274,7 @@ class Bottle
end end
def bintray def bintray
"#{name}-#{version}#{extname}" ERB::Util.url_encode("#{name}-#{version}#{extname}")
end end
def extname def extname

View File

@ -78,7 +78,7 @@ module Homebrew
case output_type case output_type
when :print when :print
args << "--debug" if ARGV.debug? args << "--debug" if ARGV.debug?
args << "--display-cop-names" if ARGV.include? "--display-cop-names" args << "--display-cop-names" if Homebrew.args.display_cop_names?
args << "--format" << "simple" if files args << "--format" << "simple" if files
system(cache_env, "rubocop", *args) system(cache_env, "rubocop", *args)
rubocop_success = $CHILD_STATUS.success? rubocop_success = $CHILD_STATUS.success?

View File

@ -12,53 +12,6 @@ RSpec/ExampleLength:
Exclude: Exclude:
- 'rubocops/patches_spec.rb' - 'rubocops/patches_spec.rb'
# Offense count: 41
# Configuration parameters: CustomTransform, IgnoreMethods.
RSpec/FilePath:
Exclude:
- 'ARGV_spec.rb'
- 'PATH_spec.rb'
- 'bottle_filename_spec.rb'
- 'cache_store_spec.rb'
- 'cask/artifact/alt_target_spec.rb'
- 'cask/artifact/generic_artifact_spec.rb'
- 'cask/artifact/two_apps_correct_spec.rb'
- 'cask/artifact/uninstall_no_zap_spec.rb'
- 'cask/cask_loader/from__path_loader_spec.rb'
- 'cask/macos_spec.rb'
- 'cli/parser_spec.rb'
- 'checksum_verification_spec.rb'
- 'cxxstdlib_spec.rb'
- 'diagnostic_checks_spec.rb'
- 'env_config_spec.rb'
- 'missing_formula_spec.rb'
- 'os/linux/diagnostic_spec.rb'
- 'os/mac/diagnostic_spec.rb'
- 'requirements/macos_requirement_spec.rb'
- 'rubocops/cask/homepage_matches_url_spec.rb'
- 'rubocops/cask/homepage_url_trailing_slash_spec.rb'
- 'rubocops/cask/no_dsl_version_spec.rb'
- 'rubocops/cask/stanza_grouping_spec.rb'
- 'rubocops/cask/stanza_order_spec.rb'
- 'rubocops/caveats_spec.rb'
- 'rubocops/components_order_spec.rb'
- 'rubocops/components_redundancy_spec.rb'
- 'rubocops/conflicts_spec.rb'
- 'rubocops/dependency_order_spec.rb'
- 'rubocops/files_spec.rb'
- 'rubocops/homepage_spec.rb'
- 'rubocops/options_spec.rb'
- 'rubocops/patches_spec.rb'
- 'rubocops/text_spec.rb'
- 'rubocops/uses_from_macos_spec.rb'
- 'rubocops/formula_desc_spec.rb'
- 'search_spec.rb'
- 'string_spec.rb'
- 'style_spec.rb'
- 'system_command_result_spec.rb'
- 'unpack_strategy/p7zip_spec.rb'
- 'utils/github_spec.rb'
# Offense count: 6 # Offense count: 6
# Configuration parameters: AssignmentOnly. # Configuration parameters: AssignmentOnly.
RSpec/InstanceVariable: RSpec/InstanceVariable:
@ -83,6 +36,7 @@ RSpec/MultipleDescribes:
- 'cmd/cleanup_spec.rb' - 'cmd/cleanup_spec.rb'
- 'cmd/commands_spec.rb' - 'cmd/commands_spec.rb'
- 'cmd/config_spec.rb' - 'cmd/config_spec.rb'
- 'cmd/deps_spec.rb'
- 'cmd/desc_spec.rb' - 'cmd/desc_spec.rb'
- 'cmd/doctor_spec.rb' - 'cmd/doctor_spec.rb'
- 'cmd/fetch_spec.rb' - 'cmd/fetch_spec.rb'

View File

@ -2,6 +2,7 @@
require_relative "shared_examples/requires_cask_token" require_relative "shared_examples/requires_cask_token"
require_relative "shared_examples/invalid_option" require_relative "shared_examples/invalid_option"
require "utils"
describe Cask::Cmd::Info, :cask do describe Cask::Cmd::Info, :cask do
it_behaves_like "a command that requires a Cask token" it_behaves_like "a command that requires a Cask token"
@ -139,7 +140,16 @@ describe Cask::Cmd::Info, :cask do
EOS EOS
end end
it "can run be run with a url twice", :needs_network do it "can run be run with a url twice and returns analytics", :needs_network do
analytics = {
"analytics" => {
"install" => {
"30d" => { "docker" => 1000 }, "90d" => { "docker" => 2000 }, "365d" => { "docker" => 3000 }
},
},
}
expect(Utils::Analytics).to receive(:formulae_brew_sh_json).twice.with("cask/docker.json")
.and_return(analytics)
expect { expect {
described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \ described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \
"/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb") "/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb")
@ -155,6 +165,8 @@ describe Cask::Cmd::Info, :cask do
Docker CE Docker CE
==> Artifacts ==> Artifacts
Docker.app (App) Docker.app (App)
==> Analytics
install: 1,000 (30 days), 2,000 (90 days), 3,000 (365 days)
==> Downloading https://raw.githubusercontent.com/Homebrew/homebrew-cask/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb. ==> Downloading https://raw.githubusercontent.com/Homebrew/homebrew-cask/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb.
docker: 2.0.0.2-ce-mac81,30215 (auto_updates) docker: 2.0.0.2-ce-mac81,30215 (auto_updates)
https://www.docker.com/community-edition https://www.docker.com/community-edition
@ -164,6 +176,8 @@ describe Cask::Cmd::Info, :cask do
Docker CE Docker CE
==> Artifacts ==> Artifacts
Docker.app (App) Docker.app (App)
==> Analytics
install: 1,000 (30 days), 2,000 (90 days), 3,000 (365 days)
EOS EOS
end end
end end

View File

@ -1,5 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
require "cmd/shared_examples/args_parse"
describe "Homebrew.deps_args" do
it_behaves_like "parseable arguments"
end
describe "brew deps", :integration_test do describe "brew deps", :integration_test do
it "outputs all of a Formula's dependencies and their dependencies on separate lines" do it "outputs all of a Formula's dependencies and their dependencies on separate lines" do
setup_test_formula "foo" setup_test_formula "foo"

View File

@ -14,6 +14,17 @@ describe "brew install", :integration_test do
.to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}).to_stdout .to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}).to_stdout
.and not_to_output.to_stderr .and not_to_output.to_stderr
.and be_a_success .and be_a_success
expect(HOMEBREW_CELLAR/"testball1/0.1/foo/test").not_to be_a_file
end
it "installs formulae with options" do
setup_test_formula "testball1"
expect { brew "install", "testball1", "--with-foo" }
.to output(%r{#{HOMEBREW_CELLAR}/testball1/0\.1}).to_stdout
.and not_to_output.to_stderr
.and be_a_success
expect(HOMEBREW_CELLAR/"testball1/0.1/foo/test").to be_a_file
end end
it "can install keg-only Formulae" do it "can install keg-only Formulae" do
@ -27,6 +38,7 @@ describe "brew install", :integration_test do
.to output(%r{#{HOMEBREW_CELLAR}/testball1/1\.0}).to_stdout .to output(%r{#{HOMEBREW_CELLAR}/testball1/1\.0}).to_stdout
.and not_to_output.to_stderr .and not_to_output.to_stderr
.and be_a_success .and be_a_success
expect(HOMEBREW_CELLAR/"testball1/1.0/foo/test").not_to be_a_file
end end
it "can install HEAD Formulae" do it "can install HEAD Formulae" do
@ -59,5 +71,6 @@ describe "brew install", :integration_test do
.to output(%r{#{HOMEBREW_CELLAR}/testball1/HEAD\-d5eb689}).to_stdout .to output(%r{#{HOMEBREW_CELLAR}/testball1/HEAD\-d5eb689}).to_stdout
.and output(/Cloning into/).to_stderr .and output(/Cloning into/).to_stderr
.and be_a_success .and be_a_success
expect(HOMEBREW_CELLAR/"testball1/HEAD-d5eb689/foo/test").not_to be_a_file
end end
end end

View File

@ -3,11 +3,12 @@
shared_examples "parseable arguments" do shared_examples "parseable arguments" do
subject(:method_name) do |example| subject(:method_name) do |example|
example.metadata[:example_group][:parent_example_group][:description] example.metadata[:example_group][:parent_example_group][:description]
.gsub(/^Homebrew\./, "") .delete_prefix("Homebrew.")
end end
let(:command_name) do let(:command_name) do
method_name.gsub(/_args$/, "").tr("_", "-") method_name.delete_suffix("_args")
.tr("_", "-")
end end
it "can parse arguments" do it "can parse arguments" do

View File

@ -300,69 +300,6 @@ module Homebrew
end end
end end
describe "#audit_keg_only" do
specify "keg_only_needs_downcasing" do
fa = formula_auditor "foo", <<~RUBY, strict: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
keg_only "Because why not"
end
RUBY
fa.audit_keg_only
expect(fa.problems)
.to eq(["'Because' from the keg_only reason should be 'because'.\n"])
end
specify "keg_only_redundant_period" do
fa = formula_auditor "foo", <<~RUBY, strict: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
keg_only "because this line ends in a period."
end
RUBY
fa.audit_keg_only
expect(fa.problems)
.to eq(["keg_only reason should not end with a period."])
end
specify "keg_only_handles_block_correctly" do
fa = formula_auditor "foo", <<~RUBY, strict: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
keg_only <<~EOF
this line starts with a lowercase word.
This line does not but that shouldn't be a
problem
EOF
end
RUBY
fa.audit_keg_only
expect(fa.problems)
.to eq([])
end
specify "keg_only_handles_whitelist_correctly" do
fa = formula_auditor "foo", <<~RUBY, strict: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
keg_only "Apple ships foo in the CLT package"
end
RUBY
fa.audit_keg_only
expect(fa.problems)
.to eq([])
end
end
describe "#audit_revision_and_version_scheme" do describe "#audit_revision_and_version_scheme" do
subject { subject {
fa = described_class.new(Formulary.factory(formula_path)) fa = described_class.new(Formulary.factory(formula_path))

View File

@ -24,7 +24,10 @@ describe FormulaInstaller do
stub_formula_loader formula("gcc") { url "gcc-1.0" } stub_formula_loader formula("gcc") { url "gcc-1.0" }
stub_formula_loader formula("patchelf") { url "patchelf-1.0" } stub_formula_loader formula("patchelf") { url "patchelf-1.0" }
allow(Formula["patchelf"]).to receive(:latest_version_installed?).and_return(true) allow(Formula["patchelf"]).to receive(:latest_version_installed?).and_return(true)
described_class.new(formula).install
fi = FormulaInstaller.new(formula)
fi.fetch
fi.install
keg = Keg.new(formula.prefix) keg = Keg.new(formula.prefix)

View File

@ -22,6 +22,7 @@ describe FormulaInstaller do
installer = described_class.new(formula) installer = described_class.new(formula)
installer.fetch
installer.install installer.install
keg = Keg.new(formula.prefix) keg = Keg.new(formula.prefix)
@ -156,6 +157,7 @@ describe FormulaInstaller do
it "shows audit problems if HOMEBREW_DEVELOPER is set" do it "shows audit problems if HOMEBREW_DEVELOPER is set" do
ENV["HOMEBREW_DEVELOPER"] = "1" ENV["HOMEBREW_DEVELOPER"] = "1"
formula_installer.fetch
formula_installer.install formula_installer.install
expect(formula_installer).to receive(:audit_installed).and_call_original expect(formula_installer).to receive(:audit_installed).and_call_original
formula_installer.caveats formula_installer.caveats

View File

@ -698,6 +698,43 @@ describe Formula do
expect(f1.test_fixtures("foo")).to eq(Pathname.new("#{HOMEBREW_LIBRARY_PATH}/test/support/fixtures/foo")) expect(f1.test_fixtures("foo")).to eq(Pathname.new("#{HOMEBREW_LIBRARY_PATH}/test/support/fixtures/foo"))
end end
specify "#livecheck" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
livecheck do
skip "foo"
url "https://brew.sh/test/releases"
regex(/test-(\d+(?:\.\d+)+)\.tbz/)
end
end
expect(f.livecheck.skip?).to be true
expect(f.livecheck.skip_msg).to eq("foo")
expect(f.livecheck.url).to eq("https://brew.sh/test/releases")
expect(f.livecheck.regex).to eq(/test-(\d+(?:\.\d+)+)\.tbz/)
end
describe "#livecheckable?" do
specify "no livecheck block defined" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
end
expect(f.livecheckable?).to be false
end
specify "livecheck block defined" do
f = formula do
url "https://brew.sh/test-1.0.tbz"
livecheck do
regex(/test-(\d+(?:.\d+)+).tbz/)
end
end
expect(f.livecheckable?).to be true
end
end
specify "dependencies" do specify "dependencies" do
f1 = formula "f1" do f1 = formula "f1" do
url "f1-1.0" url "f1-1.0"

View File

@ -149,6 +149,7 @@ describe Formulary do
let(:installer) { FormulaInstaller.new(installed_formula) } let(:installer) { FormulaInstaller.new(installed_formula) }
it "returns a Formula when given a rack" do it "returns a Formula when given a rack" do
installer.fetch
installer.install installer.install
f = described_class.from_rack(installed_formula.rack) f = described_class.from_rack(installed_formula.rack)
@ -156,6 +157,7 @@ describe Formulary do
end end
it "returns a Formula when given a Keg" do it "returns a Formula when given a Keg" do
installer.fetch
installer.install installer.install
keg = Keg.new(installed_formula.prefix) keg = Keg.new(installed_formula.prefix)

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
require "livecheck"
describe Livecheck do
subject(:livecheckable) { described_class.new }
describe "#regex" do
it "returns nil if unset" do
expect(livecheckable.regex).to be nil
end
it "returns the Regex if set" do
livecheckable.regex(/foo/)
expect(livecheckable.regex).to eq(/foo/)
end
end
describe "#skip" do
it "sets the instance variable skip to true and skip_msg to nil when the argument is not present" do
livecheckable.skip
expect(livecheckable.instance_variable_get(:@skip)).to be true
expect(livecheckable.instance_variable_get(:@skip_msg)).to be nil
end
it "sets the instance variable skip to true and skip_msg to the argument when present" do
livecheckable.skip("foo")
expect(livecheckable.instance_variable_get(:@skip)).to be true
expect(livecheckable.instance_variable_get(:@skip_msg)).to eq("foo")
end
end
describe "#skip?" do
it "returns the value of the instance variable skip" do
expect(livecheckable.skip?).to be false
livecheckable.skip
expect(livecheckable.skip?).to be true
end
end
describe "#url" do
it "returns nil if unset" do
expect(livecheckable.url).to be nil
end
it "returns the URL if set" do
livecheckable.url("foo")
expect(livecheckable.url).to eq("foo")
end
end
describe "#to_hash" do
it "returns a Hash of all instance variables" do
expect(livecheckable.to_hash).to eq({ "regex"=>nil, "skip"=>false, "skip_msg"=>nil, "url"=>nil })
end
end
end

View File

@ -76,8 +76,8 @@ describe Messages do
# rubocop:disable RSpec/VerifiedDoubles # rubocop:disable RSpec/VerifiedDoubles
context "when the --display-times argument is present" do context "when the --display-times argument is present" do
before do before do
allow(Homebrew).to receive(:args) allow(Homebrew).to receive(:args).and_return \
.and_return(double(display_times?: true, flags_only: ["--display-times"])) double(display_times?: true, flags_only: ["--display-times"])
end end
context "when install_times is empty" do context "when install_times is empty" do

View File

@ -3,6 +3,43 @@
require "formula" require "formula"
describe Formula do describe Formula do
describe "#uses_from_macos" do
before do
allow(OS).to receive(:mac?).and_return(true)
allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra))
end
it "adds a macOS dependency to all specs if the OS version meets requirements" do
f = formula "foo" do
url "foo-1.0"
uses_from_macos("foo", since: :el_capitan)
end
expect(f.class.stable.deps).to be_empty
expect(f.class.devel.deps).to be_empty
expect(f.class.head.deps).to be_empty
expect(f.class.stable.uses_from_macos_elements.first).to eq("foo")
expect(f.class.devel.uses_from_macos_elements.first).to eq("foo")
expect(f.class.head.uses_from_macos_elements.first).to eq("foo")
end
it "doesn't add a macOS dependency to any spec if the OS version doesn't meet requirements" do
f = formula "foo" do
url "foo-1.0"
uses_from_macos("foo", since: :high_sierra)
end
expect(f.class.stable.deps.first.name).to eq("foo")
expect(f.class.devel.deps.first.name).to eq("foo")
expect(f.class.head.deps.first.name).to eq("foo")
expect(f.class.stable.uses_from_macos_elements).to be_empty
expect(f.class.devel.uses_from_macos_elements).to be_empty
expect(f.class.head.uses_from_macos_elements).to be_empty
end
end
describe "#on_macos" do describe "#on_macos" do
it "defines an url on macos only" do it "defines an url on macos only" do
f = formula do f = formula do

View File

@ -19,6 +19,23 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
RUBY RUBY
end end
it "When `bottle` precedes `livecheck`" do
expect_offense(<<~RUBY)
class Foo < Formula
homepage "https://brew.sh"
url "https://brew.sh/foo-1.0.tgz"
bottle :unneeded
livecheck do
^^^^^^^^^^^^ `livecheck` (line 7) should be put before `bottle` (line 5)
url "https://brew.sh/foo/versions/"
regex(/href=.+?foo-(\d+(?:\.\d+)+)\.t/)
end
end
RUBY
end
it "When url precedes homepage" do it "When url precedes homepage" do
expect_offense(<<~RUBY) expect_offense(<<~RUBY)
class Foo < Formula class Foo < Formula

View File

@ -0,0 +1,74 @@
# frozen_string_literal: true
require "rubocops/keg_only"
describe RuboCop::Cop::FormulaAudit::KegOnly do
subject(:cop) { described_class.new }
specify "keg_only_needs_downcasing" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
homepage "https://brew.sh"
keg_only "Because why not"
^^^^^^^^^^^^^^^^^^^^^^^^^^ 'Because' from the keg_only reason should be 'because'.
end
RUBY
end
specify "keg_only_redundant_period" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
homepage "https://brew.sh"
keg_only "ending with a period."
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ keg_only reason should not end with a period.
end
RUBY
end
specify "keg_only_handles_block_correctly" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
homepage "https://brew.sh"
keg_only <<~EOF
this line starts with a lowercase word.
This line does not but that shouldn't be a
problem
EOF
end
RUBY
end
specify "keg_only_handles_whitelist_correctly" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
homepage "https://brew.sh"
keg_only "Apple ships foo in the CLT package"
end
RUBY
end
specify "keg_only does not need downcasing of formula name in reason" do
filename = Formulary.core_path("foo")
File.open(filename, "w") do |file|
FileUtils.chmod "-rwx", filename
expect_no_offenses(<<~RUBY, file)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
keg_only "Foo is the formula name hence downcasing is not required"
end
RUBY
end
end
end

View File

@ -68,7 +68,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5, line: 5,
column: 33, column: 33,
source: source }] source: source }]
elsif patch_url.match?(%r{^http://trac\.macports\.org}) elsif patch_url.start_with?("http://trac.macports.org")
[{ message: [{ message:
<<~EOS.chomp, <<~EOS.chomp,
Patches from MacPorts Trac should be https://, not http: Patches from MacPorts Trac should be https://, not http:
@ -78,7 +78,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5, line: 5,
column: 5, column: 5,
source: source }] source: source }]
elsif patch_url.match?(%r{^http://bugs\.debian\.org}) elsif patch_url.start_with?("http://bugs.debian.org")
[{ message: [{ message:
<<~EOS.chomp, <<~EOS.chomp,
Patches from Debian should be https://, not http: Patches from Debian should be https://, not http:
@ -205,7 +205,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5, line: 5,
column: 37, column: 37,
source: source }] source: source }]
elsif patch_url.match?(%r{^http://trac\.macports\.org}) elsif patch_url.start_with?("http://trac.macports.org")
[{ message: [{ message:
<<~EOS.chomp, <<~EOS.chomp,
Patches from MacPorts Trac should be https://, not http: Patches from MacPorts Trac should be https://, not http:
@ -215,7 +215,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5, line: 5,
column: 9, column: 9,
source: source }] source: source }]
elsif patch_url.match?(%r{^http://bugs\.debian\.org}) elsif patch_url.start_with?("http://bugs.debian.org")
[{ message: [{ message:
<<~EOS.chomp, <<~EOS.chomp,
Patches from Debian should be https://, not http: Patches from Debian should be https://, not http:

View File

@ -159,6 +159,26 @@ describe RuboCop::Cop::FormulaAudit::Urls do
"not a source archive; homebrew/core is source-only.", "not a source archive; homebrew/core is source-only.",
"col" => 2, "col" => 2,
"formula_tap" => "homebrew-core", "formula_tap" => "homebrew-core",
}, {
"url" => "cvs://brew.sh/foo/bar",
"msg" => "Use of the cvs:// scheme is deprecated, pass `:using => :cvs` instead",
"col" => 2,
}, {
"url" => "bzr://brew.sh/foo/bar",
"msg" => "Use of the bzr:// scheme is deprecated, pass `:using => :bzr` instead",
"col" => 2,
}, {
"url" => "hg://brew.sh/foo/bar",
"msg" => "Use of the hg:// scheme is deprecated, pass `:using => :hg` instead",
"col" => 2,
}, {
"url" => "fossil://brew.sh/foo/bar",
"msg" => "Use of the fossil:// scheme is deprecated, pass `:using => :fossil` instead",
"col" => 2,
}, {
"url" => "svn+http://brew.sh/foo/bar",
"msg" => "Use of the svn+http:// scheme is deprecated, pass `:using => :svn` instead",
"col" => 2,
}] }]
} }

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
require "rubocops/version"
describe RuboCop::Cop::FormulaAudit::Version do
subject(:cop) { described_class.new }
context "When auditing version" do
it "version should not be an empty string" do
expect_offense(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
version ""
^^^^^^^^^^ version is set to an empty string
end
RUBY
end
it "version should not have a leading 'v'" do
expect_offense(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
version "v1.0"
^^^^^^^^^^^^^^ version v1.0 should not have a leading 'v'
end
RUBY
end
it "version should not end with underline and number" do
expect_offense(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
version "1_0"
^^^^^^^^^^^^^ version 1_0 should not end with an underline and a number
end
RUBY
end
end
end

View File

@ -39,6 +39,7 @@ require "rspec/retry"
require "rubocop" require "rubocop"
require "rubocop/rspec/support" require "rubocop/rspec/support"
require "find" require "find"
require "byebug"
$LOAD_PATH.push(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/test/support/lib")) $LOAD_PATH.push(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/test/support/lib"))
@ -177,7 +178,7 @@ RSpec.configure do |config|
@__stdout = $stdout.clone @__stdout = $stdout.clone
@__stderr = $stderr.clone @__stderr = $stderr.clone
unless example.metadata.key?(:focus) || ENV.key?("VERBOSE_TESTS") if (example.metadata.keys & [:focus, :byebug]).empty? && !ENV.key?("VERBOSE_TESTS")
$stdout.reopen(File::NULL) $stdout.reopen(File::NULL)
$stderr.reopen(File::NULL) $stderr.reopen(File::NULL)
end end

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