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

4
.gitignore vendored
View File

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

View File

@ -1,5 +1,6 @@
FROM ubuntu:xenial
LABEL maintainer="Shaun Jackman <sjackman@gmail.com>"
ARG version=20.04
FROM ubuntu:$version
ARG DEBIAN_FRONTEND=noninteractive
# hadolint ignore=DL3008
RUN apt-get update \
@ -14,6 +15,7 @@ RUN apt-get update \
fonts-dejavu-core \
g++ \
git \
less \
libz-dev \
locales \
make \
@ -23,29 +25,23 @@ RUN apt-get update \
sudo \
uuid-runtime \
tzdata \
&& rm -rf /var/lib/apt/lists/*
RUN localedef -i en_US -f UTF-8 en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/* \
&& localedef -i en_US -f UTF-8 en_US.UTF-8 \
&& useradd -m -s /bin/bash linuxbrew \
&& echo 'linuxbrew ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers
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
RUN cd /home/linuxbrew/.linuxbrew \
&& mkdir -p bin etc include lib opt sbin share var/homebrew/linked Cellar \
&& ln -s ../Homebrew/bin/brew /home/linuxbrew/.linuxbrew/bin/ \
&& cd /home/linuxbrew/.linuxbrew/Homebrew \
&& git remote set-url origin https://github.com/Homebrew/brew
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 \
&& git -C /home/linuxbrew/.linuxbrew/Homebrew remote set-url origin https://github.com/Homebrew/brew \
&& HOMEBREW_NO_ANALYTICS=1 HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/core \
&& 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.
RSpec/AnyInstance:
Enabled: false
RSpec/FilePath:
Enabled: false
RSpec/ImplicitBlockExpectation:
Enabled: false
RSpec/SubjectStub:
Enabled: false
# TODO: try to enable these (also requires fixing Homebrew/bundle)
# TODO: try to enable these
RSpec/ContextWording:
Enabled: false
RSpec/DescribeClass:
@ -34,7 +36,7 @@ RSpec/RepeatedDescription:
RSpec/RepeatedExampleGroupDescription:
Enabled: false
# TODO: try to reduce these (also requires fixing Homebrew/bundle)
# TODO: try to reduce these
RSpec/ExampleLength:
Max: 75
RSpec/MultipleExpectations:

View File

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

View File

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

View File

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

View File

@ -106,12 +106,12 @@ class Bintray
formula_packaged = {}
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_repo = bottle_hash["bintray"]["repository"]
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"]
odebug "Checking remote file #{@bintray_org}/#{bintray_repo}/#{filename}"
@ -132,7 +132,7 @@ class Bintray
formula_packaged[formula_name] = true
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"],
repo: bintray_repo,
package: bintray_package,

View File

@ -93,6 +93,30 @@ case "$HOMEBREW_SYSTEM" in
Linux) HOMEBREW_LINUX="1" ;;
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" ]]
then
HOMEBREW_PROCESSOR="$(uname -p)"
@ -159,24 +183,44 @@ else
# Ensure the system Curl is a version that supports modern HTTPS certificates.
HOMEBREW_MINIMUM_CURL_VERSION="7.41.0"
system_curl_version_output="$($(command -v curl) --version 2>/dev/null)"
system_curl_name_and_version="${system_curl_version_output%% (*}"
if [[ $(numeric "${system_curl_name_and_version##* }") -lt $(numeric "$HOMEBREW_MINIMUM_CURL_VERSION") ]]
curl_version_output="$($HOMEBREW_CURL --version 2>/dev/null)"
curl_name_and_version="${curl_version_output%% (*}"
if [[ $(numeric "${curl_name_and_version##* }") -lt $(numeric "$HOMEBREW_MINIMUM_CURL_VERSION") ]]
then
HOMEBREW_SYSTEM_CURL_TOO_OLD="1"
HOMEBREW_FORCE_BREWED_CURL="1"
if [[ -z $HOMEBREW_CURL_PATH ]]; then
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
# 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).
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.
# 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") ]]
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
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_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)"
curl_version_output="$("$HOMEBREW_CURL" --version 2>/dev/null)"
curl_name_and_version="${curl_version_output%% (*}"

View File

@ -52,6 +52,8 @@ class Build
Requirement.prune
elsif req.prune_if_build_and_not_dependent?(dependent, formula)
Requirement.prune
elsif req.test?
Requirement.prune
end
end
end
@ -65,6 +67,8 @@ class Build
Dependency.prune
elsif dep.build?
Dependency.keep_but_prune_recursive_deps
elsif dep.test?
Dependency.prune
end
end
end
@ -114,7 +118,9 @@ class Build
with_env(new_env) do
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,
# which is not known until after the formula has been staged.
ENV["HOMEBREW_FORMULA_PREFIX"] = formula.prefix

View File

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

View File

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

View File

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

View File

@ -3,17 +3,26 @@
module Cask
class Cmd
class Help < AbstractCommand
def initialize(*)
super
return if args.empty?
raise ArgumentError, "#{self.class.command_name} does not take arguments."
end
def run
puts self.class.purpose
puts
puts self.class.usage
if args.empty?
puts self.class.purpose
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
def self.purpose
@ -23,6 +32,10 @@ module Cask
EOS
end
def self.commands
Cmd.command_classes.select(&:visible?).map { |klass| [klass.command_name, klass] }.to_h
end
def self.usage
max_command_len = Cmd.commands.map(&:length).max

View File

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

View File

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

View File

@ -7,11 +7,6 @@ module Cask
option "--versions", :versions, 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
args.any? ? list : list_installed
end

View File

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

View File

@ -142,14 +142,18 @@ module Homebrew
cleanup = Cleanup.new
if cleanup.periodic_clean_due?
cleanup.periodic_clean!
elsif f.installed?
elsif f.latest_version_installed?
cleanup.cleanup_formula(f)
end
end
def periodic_clean_due?
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
end

View File

@ -5,56 +5,54 @@ require "ostruct"
module Homebrew
module CLI
class Args < OpenStruct
attr_reader :processed_options, :args_parsed
attr_reader :options_only, :flags_only
# undefine tap to allow --tap argument
undef tap
def initialize
super
def initialize(argv = ARGV.dup.freeze, set_default_args: false)
super()
self[:remaining] = []
self[:cmdline_args] = ARGV.dup.freeze
@args_parsed = false
@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
def freeze_processed_options!(processed_options)
# Reset cache values reliant on processed_options
@cli_args = nil
@processed_options += processed_options
@processed_options.freeze
@args_parsed = true
end
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
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?("--") }
@options_only = args_options_only(cli_args)
@flags_only = args_flags_only(cli_args)
end
def passthrough
@ -62,7 +60,7 @@ module Homebrew
end
def named
remaining
named_args || []
end
def no_named?
@ -74,46 +72,50 @@ module Homebrew
def collect_build_args
build_flags = []
build_flags << "--HEAD" if head
build_flags << "--universal" if build_universal
build_flags << "--build-bottle" if build_bottle
build_flags << "--build-from-source" if build_from_source
build_flags << "--HEAD" if HEAD?
build_flags << "--universal" if build_universal?
build_flags << "--build-bottle" if build_bottle?
build_flags << "--build-from-source" if build_from_source?
build_flags
end
def formulae
require "formula"
@formulae ||= (downcased_unique_named - casks).map do |name|
if name.include?("/") || File.exist?(name)
Formulary.factory(name, spec)
else
Formulary.find_with_priority(name, spec)
end
end.uniq(&:name)
end.uniq(&:name).freeze
end
def resolved_formulae
require "formula"
@resolved_formulae ||= (downcased_unique_named - casks).map do |name|
Formulary.resolve(name, spec: spec(nil))
end.uniq(&:name)
end.uniq(&:name).freeze
end
def formulae_paths
@formulae_paths ||= (downcased_unique_named - casks).map do |name|
Formulary.path(name)
end.uniq
end.uniq.freeze
end
def casks
@casks ||= downcased_unique_named.grep HOMEBREW_CASK_TAP_CASK_REGEX
@casks ||= downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX)
.freeze
end
def kegs
require "keg"
require "formula"
require "missing_formula"
@kegs ||= downcased_unique_named.map do |name|
raise UsageError if name.empty?
@ -158,7 +160,7 @@ module Homebrew
Please delete (with rm -rf!) all but one and then try again.
EOS
end
end
end.freeze
end
def build_stable?
@ -168,39 +170,56 @@ module Homebrew
# Whether a given formula should be built from source during the current
# installation run.
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 }
end
def build_from_source
return true if args_parsed && (build_from_source? || s?)
def include_formula_test_deps?(f)
return false unless include_test?
cmdline_args.include?("--build-from-source") || cmdline_args.include?("-s")
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")
formulae.any? { |args_f| args_f.full_name == f.full_name }
end
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
# Only lowercase names, not paths, bottle filenames or URLs
arguments = if args_parsed
named
else
cmdline_args.reject { |arg| arg.start_with?("-") }
end
arguments.map do |arg|
named.map do |arg|
if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
arg
else
@ -209,28 +228,10 @@ module Homebrew
end.uniq
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)
if head
if HEAD?
:head
elsif devel
elsif devel?
:devel
else
default

View File

@ -3,6 +3,7 @@
require "cli/args"
require "optparse"
require "set"
require "formula"
COMMAND_DESC_WIDTH = 80
OPTION_DESC_WIDTH = 43
@ -12,8 +13,8 @@ module Homebrew
class Parser
attr_reader :processed_options, :hide_from_man_page
def self.parse(args = ARGV, allow_no_named_args: false, &block)
new(args, &block).parse(args, allow_no_named_args: allow_no_named_args)
def self.parse(argv = ARGV.dup.freeze, allow_no_named_args: false, &block)
new(argv, &block).parse(allow_no_named_args: allow_no_named_args)
end
def self.from_cmd_path(cmd_path)
@ -37,9 +38,10 @@ module Homebrew
}
end
def initialize(&block)
def initialize(argv = ARGV.dup.freeze, &block)
@parser = OptionParser.new
@args = Homebrew::CLI::Args.new
@argv = argv
@args = Homebrew::CLI::Args.new(@argv)
@constraints = []
@conflicts = []
@ -152,21 +154,22 @@ module Homebrew
@parser.to_s
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
begin
named_args = @parser.parse(cmdline_args)
named_args = @parser.parse(argv)
rescue OptionParser::InvalidOption => e
$stderr.puts generate_help_text
raise e
end
check_constraint_violations
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)
Homebrew.args = @args
cmdline_args.freeze
@args_parsed = true
@parser
end
@ -186,7 +189,7 @@ module Homebrew
end
def formula_options
@args.formulae.each do |f|
formulae.each do |f|
next if f.options.empty?
f.options.each do |o|
@ -341,6 +344,28 @@ module Homebrew
option, = @parser.make_switch(args)
@processed_options << [option.short.first, option.long.first, option.arg, option.desc.first]
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
class OptionConstraintError < RuntimeError

View File

@ -152,7 +152,7 @@ module Homebrew
end
# --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
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.interactive = args.interactive?
fi.git = args.git?
fi.fetch
fi.prelude
fi.install
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`.
#:
#: 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() {
case "$SHELL" in

View File

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

View File

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

View File

@ -80,6 +80,30 @@ module Homebrew
puts "#{keg.name} #{versions.to_sentence} #{"is".pluralize(versions.count)} still installed."
puts "Run `brew uninstall --force #{keg.name}` to remove all versions."
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

View File

@ -183,7 +183,6 @@ module Homebrew
fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request ||= tab.installed_on_request
end
fi.prelude
upgrade_version = if f.optlinked?
"#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
@ -192,6 +191,9 @@ module Homebrew
end
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
# possible for the existing build to interfere with the build we are about to
# do! Seriously, it happens!

View File

@ -4,3 +4,4 @@ require "compat/cask/dsl/version"
require "compat/language/python"
require "compat/requirements/macos_requirement"
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
# 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
rescue FormulaUnavailableError
GNU_GCC_VERSIONS

View File

@ -81,7 +81,7 @@ module Homebrew
ignores << "optional?"
end
ignores << "recommended?" if ARGV.include? "--skip-recommended"
ignores << "recommended?" if Homebrew.args.skip_recommended?
[includes, ignores]
end
@ -100,16 +100,11 @@ module Homebrew
klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.optional?
klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.test?
if includes.include?("test?")
Dependency.keep_but_prune_recursive_deps if type == :dependencies
elsif dep.build?
klass.prune unless includes.include?("build?")
else
klass.prune
end
elsif dep.build?
klass.prune unless includes.include?("build?")
elsif dep.build? || dep.test?
keep = false
keep ||= dep.test? && includes.include?("test?") && dependent == formula
keep ||= dep.build? && includes.include?("build?")
klass.prune unless keep
end
# 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|
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)
when :prune
next

View File

@ -435,40 +435,6 @@ module Homebrew
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
return unless formula.name == "postgresql"
return unless @core_tap
@ -1018,7 +984,7 @@ module Homebrew
except_audits = @except
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
next unless only_audits.include?(name)
elsif except_audits
@ -1076,9 +1042,6 @@ module Homebrew
def audit_version
if version.nil?
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?
version_text = version
version_url = Version.detect(url, specs)
@ -1086,26 +1049,12 @@ module Homebrew
problem "version #{version_text} is redundant with version scanned from URL"
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
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)
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]
end

View File

@ -118,12 +118,6 @@ module Homebrew
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
if new_url && !formula
# Split the new URL on / and find any formulae that have the same URL
@ -152,7 +146,8 @@ module Homebrew
end
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?
devel_message = " (devel)"

View File

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

View File

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

View File

@ -16,9 +16,11 @@ module Homebrew
flag "--tap=",
description: "Target tap repository (default: `homebrew/core`)."
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=",
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",
description: "Run `brew pr-publish` on matching pull requests."
switch "--ignore-failures",
@ -33,12 +35,13 @@ module Homebrew
pr_automerge_args.parse
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"]
tap = Tap.fetch(Homebrew.args.tap || CoreTap.instance.name)
query = "is:pr is:open repo:#{tap.full_name} label:\"#{with_label}\""
query += args.ignore_failures? ? " -status:pending" : " status:success"
query = "is:pr is:open repo:#{tap.full_name}"
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}\"" }
odebug "Searching: #{query}"

View File

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

View File

@ -78,7 +78,7 @@ class DevelopmentTools
path = HOMEBREW_PREFIX/"opt/gcc/bin"/cc
path = locate(cc) unless path.exist?
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
else
Version::NULL

View File

@ -3,6 +3,7 @@
require "keg"
require "language/python"
require "formula"
require "formulary"
require "version"
require "development_tools"
require "utils/shell"
@ -832,6 +833,23 @@ module Homebrew
EOS
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
methods.map(&:to_s).grep(/^check_/)
end

View File

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

View File

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

View File

@ -235,20 +235,6 @@ module SharedEnvExtension
ohai "Building with an alternative Fortran compiler"
puts "This is unsupported."
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
if (gfortran = which("gfortran", (HOMEBREW_PREFIX/"bin").to_s))
ohai "Using Homebrew-provided Fortran compiler."
@ -268,8 +254,8 @@ module SharedEnvExtension
# @private
def effective_arch
if Homebrew.args.build_bottle && ARGV.bottle_arch
ARGV.bottle_arch
if Homebrew.args.build_bottle? && Homebrew.args.bottle_arch
Homebrew.args.bottle_arch.to_sym
else
Hardware.oldest_cpu
end

View File

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

View File

@ -80,7 +80,7 @@ module Hardware
# Compatibility with Mac method, which returns lowercase symbols
# instead of strings
def features
@features ||= flags[1..-1].map(&:intern)
@features ||= flags[1..].map(&:intern)
end
%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.
EOS
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

View File

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

View File

@ -5,7 +5,7 @@ module Homebrew
module_function
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 if Homebrew.args.build_formula_from_source?(f)
return false unless f.bottle.compatible_cellar?

View File

@ -12,6 +12,7 @@ require "build_environment"
require "build_options"
require "formulary"
require "software_spec"
require "livecheck"
require "install_renamed"
require "pkg_version"
require "keg"
@ -125,6 +126,7 @@ class Formula
# The currently active {SoftwareSpec}.
# @see #determine_active_spec
attr_reader :active_spec
protected :active_spec
# A symbol to indicate currently active {SoftwareSpec}.
@ -175,6 +177,7 @@ class Formula
# Defaults to true.
# @return [Boolean]
attr_accessor :follow_installed_alias
alias follow_installed_alias? follow_installed_alias
# @private
@ -353,6 +356,16 @@ class Formula
# @see .homepage=
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 is autodetected from the URL and/or tag so only needs to be
# declared if it cannot be autodetected correctly.
@ -790,6 +803,14 @@ class Formula
(HOMEBREW_PREFIX/"etc").extend(InstallRenamed)
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.
# This directory is not inside the `HOMEBREW_CELLAR` so it persists
# across upgrades.
@ -991,11 +1012,11 @@ class Formula
self.build = Tab.for_formula(self)
new_env = {
"TMPDIR" => HOMEBREW_TEMP,
"TEMP" => HOMEBREW_TEMP,
"TMP" => HOMEBREW_TEMP,
"HOMEBREW_PATH" => nil,
"PATH" => ENV["HOMEBREW_PATH"],
TMPDIR: HOMEBREW_TEMP,
TEMP: HOMEBREW_TEMP,
TMP: HOMEBREW_TEMP,
HOMEBREW_PATH: nil,
PATH: ENV["HOMEBREW_PATH"],
}
with_env(new_env) do
@ -1080,7 +1101,7 @@ class Formula
# keg's formula is deleted.
begin
keg = Keg.for(path)
rescue NotAKegError, Errno::ENOENT # rubocop:disable Lint/SuppressedException
rescue NotAKegError, Errno::ENOENT
# file doesn't belong to any keg.
else
tab_tap = Tab.for_keg(keg).tap
@ -1089,7 +1110,7 @@ class Formula
begin
Formulary.factory(keg.name)
rescue FormulaUnavailableError # rubocop:disable Lint/SuppressedException
rescue FormulaUnavailableError
# formula for this keg is deleted, so defer to whitelist
rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
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
# where staging is a Mktemp staging context
# @private
def brew
def brew(fetch: true)
@prefix_returns_versioned_prefix = true
active_spec.fetch if fetch
stage do |staging|
staging.retain! if Homebrew.args.keep_tmp?
prepare_patches
fetch_patches if fetch
begin
yield self, staging
@ -1203,7 +1227,7 @@ class Formula
next if version.head?
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
# 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|
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?
bottle_spec = spec.bottle_specification
@ -1713,11 +1744,6 @@ class Formula
}
end
hsh["bottle"][spec_sym] = bottle_info
hsh["urls"][spec_sym] = {
"url" => spec.url,
"tag" => spec.specs[:tag],
"revision" => spec.specs[:revision],
}
end
hsh["options"] = options.map do |opt|
@ -2057,8 +2083,17 @@ class Formula
ENV.update(removed)
end
def fetch_patches
patchlist.select(&:external?).each(&:fetch)
end
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.
# @private
def versioned_prefix(v)
@ -2126,13 +2161,6 @@ class Formula
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.
class << self
include BuildEnvironment::DSL
@ -2178,6 +2206,13 @@ class Formula
# <pre>homepage "https://www.example.com"</pre>
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}.
# @private
attr_reader :plist_startup
@ -2620,6 +2655,26 @@ class Formula
define_method(:test, &block)
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
# installation.
#

View File

@ -224,6 +224,41 @@ module FormulaCellarChecks
EOS
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
@new_formula ||= false
@ -240,6 +275,7 @@ module FormulaCellarChecks
problem_if_output(check_elisp_root(formula.share, formula.name))
problem_if_output(check_python_packages(formula.lib, formula.deps))
problem_if_output(check_shim_references(formula.prefix))
problem_if_output(check_plist(formula.prefix, formula.plist))
end
alias generic_audit_installed audit_installed

View File

@ -25,6 +25,7 @@ class FormulaInstaller
def self.mode_attr_accessor(*names)
attr_accessor(*names)
private(*names)
names.each do |name|
predicate = "#{name}?"
@ -38,6 +39,7 @@ class FormulaInstaller
attr_reader :formula
attr_accessor :options, :build_bottle
attr_accessor :installed_as_dependency, :installed_on_request, :link_keg
mode_attr_accessor :show_summary_heading, :show_header
mode_attr_accessor :build_from_source, :force_bottle, :include_test
mode_attr_accessor :ignore_deps, :only_deps, :interactive, :git
@ -49,10 +51,10 @@ class FormulaInstaller
@show_header = false
@ignore_deps = false
@only_deps = false
@build_from_source = Homebrew.args.build_from_source
@build_from_source = Homebrew.args.build_from_source?
@build_bottle = false
@force_bottle = Homebrew.args.force_bottle
@include_test = ARGV.include?("--include-test")
@force_bottle = Homebrew.args.force_bottle?
@include_test = Homebrew.args.include_test?
@interactive = false
@git = false
@verbose = Homebrew.args.verbose?
@ -267,7 +269,7 @@ class FormulaInstaller
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}"
end
@ -277,7 +279,7 @@ class FormulaInstaller
opoo "#{formula.full_name}: #{old_flag} was deprecated; using #{new_flag} instead!"
end
options = display_options(formula)
options = display_options(formula).join(" ")
oh1 "Installing #{Formatter.identifier(formula.full_name)} #{options}".strip if show_header?
unless formula.tap&.private?
@ -451,13 +453,16 @@ class FormulaInstaller
build = effective_build_options_for(dependent)
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)
Requirement.prune
elsif req.satisfied?
Requirement.prune
elsif include_test? && req.test?
next
elsif !runtime_requirements.include?(req) && install_bottle_for_dependent
elsif (req.build? || req.test?) && !keep_build_test
Requirement.prune
elsif (dep = formula_deps_map[dependent.name]) && dep.build?
Requirement.prune
@ -484,13 +489,13 @@ class FormulaInstaller
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)
Dependency.prune
elsif include_test? && dep.test? && !dep.installed?
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)
elsif (dep.build? || dep.test?) && !keep_build_test
Dependency.prune
elsif dep.satisfied?(inherited_options[dep.name])
Dependency.skip
@ -527,16 +532,15 @@ class FormulaInstaller
end
def display_options(formula)
options = []
if formula.head?
options << "--HEAD"
options = if formula.head?
["--HEAD"]
elsif formula.devel?
options << "--devel"
["--devel"]
else
[]
end
options += effective_build_options_for(formula).used_options.to_a
return if options.empty?
options.join(" ")
options
end
def inherited_options_for(dep)
@ -561,6 +565,23 @@ class FormulaInstaller
@show_header = true unless deps.empty?
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)
df = dep.to_formula
tab = Tab.for_formula(df)
@ -593,6 +614,7 @@ class FormulaInstaller
fi.options &= df.options
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?
@ -699,7 +721,7 @@ class FormulaInstaller
if 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
args << "--git" if git?
@ -707,7 +729,6 @@ class FormulaInstaller
args << "--verbose" if verbose?
args << "--debug" if debug?
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?
if ARGV.env
@ -776,7 +797,7 @@ class FormulaInstaller
rescue Exception => e # rubocop:disable Lint/RescueException
if e.is_a? BuildError
e.formula = formula
e.options = options
e.options = display_options(formula)
end
ignore_interrupts do
@ -947,14 +968,38 @@ class FormulaInstaller
@show_summary_heading = true
end
def pour
if (bottle_path = formula.local_bottle_path)
downloader = LocalBottleDownloadStrategy.new(bottle_path)
else
downloader = formula.bottle
downloader.fetch
def fetch_dependencies
deps = compute_dependencies
return if deps.empty? || ignore_deps?
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
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
downloader.stage
end

View File

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

View File

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

View File

@ -103,7 +103,7 @@ module Homebrew
help_lines = command_help_lines(path)
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(/^\* /, "#{Tty.bold}Usage: brew#{Tty.reset} ")
.gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}")

View File

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

View File

@ -1,96 +1,3 @@
# frozen_string_literal: true
module Language
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
require "compat/language/haskell"

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`:
This variable may contain any arguments normally used as options on
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'

View File

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

View File

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

View File

@ -166,14 +166,6 @@ module OS
paths.uniq
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)
path = mdfind(*ids)
.reject { |p| p.include?("/Backups.backupdb/") }
@ -196,13 +188,5 @@ module OS
def mdfind_query(*ids)
ids.map! { |id| "kMDItemCFBundleIdentifier == #{id}" }.join(" || ")
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

View File

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

View File

@ -25,7 +25,7 @@ module Homebrew
fi = FormulaInstaller.new(f)
fi.options = options
fi.build_bottle = Homebrew.args.build_bottle
fi.build_bottle = Homebrew.args.build_bottle?
fi.interactive = Homebrew.args.interactive?
fi.git = Homebrew.args.git?
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_on_request = tab.installed_on_request
end
fi.fetch
fi.prelude
oh1 "Reinstalling #{Formatter.identifier(f.full_name)} #{options.to_a.join " "}"

View File

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

View File

@ -55,6 +55,10 @@ class Resource
"#{owner.name}--#{escaped_name}"
end
def downloaded?
cached_download.exist?
end
def cached_download
downloader.cached_location
end
@ -68,16 +72,23 @@ class Resource
# directory. Subclasses that override stage should implement the tmp
# dir using {Mktemp} so that works with all subtypes.
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
fetch_patches(skip_downloaded: true)
fetch unless downloaded?
unpack(target, &block)
end
def prepare_patches
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
def apply_patches
@ -114,6 +125,8 @@ class Resource
def fetch(verify_download_integrity: true)
HOMEBREW_CACHE.mkpath
fetch_patches
begin
downloader.fetch
rescue ErrorDuringExecution, CurlDownloadStrategyError => e

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,6 +17,7 @@ module RuboCop
include RangeHelp
attr_accessor :file_path
@registry = Cop.registry
# 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]}`"
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|
urls.each do |url|
url_string = string_content(parameters(url).first)
@ -220,7 +230,7 @@ module RuboCop
# Use new-style archive downloads
archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/}
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})."
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 "global"
require "os/mac/version"
require "cli/parser"
class SoftwareSpec
extend Forwardable
@ -96,7 +95,7 @@ class SoftwareSpec
def bottled?
bottle_specification.tag?(Utils::Bottles.tag) && \
(bottle_specification.compatible_cellar? || Homebrew.args.force_bottle)
(bottle_specification.compatible_cellar? || Homebrew.args.force_bottle?)
end
def bottle(disable_type = nil, disable_reason = nil, &block)
@ -275,7 +274,7 @@ class Bottle
end
def bintray
"#{name}-#{version}#{extname}"
ERB::Util.url_encode("#{name}-#{version}#{extname}")
end
def extname

View File

@ -78,7 +78,7 @@ module Homebrew
case output_type
when :print
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
system(cache_env, "rubocop", *args)
rubocop_success = $CHILD_STATUS.success?

View File

@ -12,53 +12,6 @@ RSpec/ExampleLength:
Exclude:
- '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
# Configuration parameters: AssignmentOnly.
RSpec/InstanceVariable:
@ -83,6 +36,7 @@ RSpec/MultipleDescribes:
- 'cmd/cleanup_spec.rb'
- 'cmd/commands_spec.rb'
- 'cmd/config_spec.rb'
- 'cmd/deps_spec.rb'
- 'cmd/desc_spec.rb'
- 'cmd/doctor_spec.rb'
- 'cmd/fetch_spec.rb'

View File

@ -2,6 +2,7 @@
require_relative "shared_examples/requires_cask_token"
require_relative "shared_examples/invalid_option"
require "utils"
describe Cask::Cmd::Info, :cask do
it_behaves_like "a command that requires a Cask token"
@ -139,7 +140,16 @@ describe Cask::Cmd::Info, :cask do
EOS
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 {
described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \
"/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb")
@ -155,6 +165,8 @@ describe Cask::Cmd::Info, :cask do
Docker CE
==> Artifacts
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.
docker: 2.0.0.2-ce-mac81,30215 (auto_updates)
https://www.docker.com/community-edition
@ -164,6 +176,8 @@ describe Cask::Cmd::Info, :cask do
Docker CE
==> Artifacts
Docker.app (App)
==> Analytics
install: 1,000 (30 days), 2,000 (90 days), 3,000 (365 days)
EOS
end
end

View File

@ -1,5 +1,11 @@
# 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
it "outputs all of a Formula's dependencies and their dependencies on separate lines" do
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
.and not_to_output.to_stderr
.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
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
.and not_to_output.to_stderr
.and be_a_success
expect(HOMEBREW_CELLAR/"testball1/1.0/foo/test").not_to be_a_file
end
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
.and output(/Cloning into/).to_stderr
.and be_a_success
expect(HOMEBREW_CELLAR/"testball1/HEAD-d5eb689/foo/test").not_to be_a_file
end
end

View File

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

View File

@ -300,69 +300,6 @@ module Homebrew
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
subject {
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("patchelf") { url "patchelf-1.0" }
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)

View File

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

View File

@ -149,6 +149,7 @@ describe Formulary do
let(:installer) { FormulaInstaller.new(installed_formula) }
it "returns a Formula when given a rack" do
installer.fetch
installer.install
f = described_class.from_rack(installed_formula.rack)
@ -156,6 +157,7 @@ describe Formulary do
end
it "returns a Formula when given a Keg" do
installer.fetch
installer.install
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
context "when the --display-times argument is present" do
before do
allow(Homebrew).to receive(:args)
.and_return(double(display_times?: true, flags_only: ["--display-times"]))
allow(Homebrew).to receive(:args).and_return \
double(display_times?: true, flags_only: ["--display-times"])
end
context "when install_times is empty" do

View File

@ -3,6 +3,43 @@
require "formula"
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
it "defines an url on macos only" do
f = formula do

View File

@ -19,6 +19,23 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
RUBY
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
expect_offense(<<~RUBY)
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,
column: 33,
source: source }]
elsif patch_url.match?(%r{^http://trac\.macports\.org})
elsif patch_url.start_with?("http://trac.macports.org")
[{ message:
<<~EOS.chomp,
Patches from MacPorts Trac should be https://, not http:
@ -78,7 +78,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5,
column: 5,
source: source }]
elsif patch_url.match?(%r{^http://bugs\.debian\.org})
elsif patch_url.start_with?("http://bugs.debian.org")
[{ message:
<<~EOS.chomp,
Patches from Debian should be https://, not http:
@ -205,7 +205,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5,
column: 37,
source: source }]
elsif patch_url.match?(%r{^http://trac\.macports\.org})
elsif patch_url.start_with?("http://trac.macports.org")
[{ message:
<<~EOS.chomp,
Patches from MacPorts Trac should be https://, not http:
@ -215,7 +215,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5,
column: 9,
source: source }]
elsif patch_url.match?(%r{^http://bugs\.debian\.org})
elsif patch_url.start_with?("http://bugs.debian.org")
[{ message:
<<~EOS.chomp,
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.",
"col" => 2,
"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/rspec/support"
require "find"
require "byebug"
$LOAD_PATH.push(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/test/support/lib"))
@ -177,7 +178,7 @@ RSpec.configure do |config|
@__stdout = $stdout.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)
$stderr.reopen(File::NULL)
end

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