Merge branch 'master' into mlh-outdated-packages

This commit is contained in:
Baffour Adu Boampong 2020-07-21 17:49:24 +00:00 committed by GitHub
commit 9ec93f78d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
295 changed files with 3688 additions and 2040 deletions

50
.github/workflows/doctor.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: brew doctor
on:
pull_request:
paths:
- .github/workflows/doctor.yml
- Library/Homebrew/cmd/doctor.rb
- Library/Homebrew/diagnostic.rb
- Library/Homebrew/extend/os/diagnostic.rb
- Library/Homebrew/extend/os/mac/diagnostic.rb
- Library/Homebrew/os/mac/xcode.rb
jobs:
tests:
strategy:
matrix:
version: [10.15, 10.14, 10.13]
fail-fast: false
runs-on: ${{ matrix.version }}
env:
PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin'
HOMEBREW_DEVELOPER: 1
HOMEBREW_NO_ANALYTICS: 1
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- name: Update Homebrew
run: brew update-reset
- name: Set up Git repository
run: |
cd $(brew --repo)
git clean -ffdx
git fetch --prune --force origin master
git fetch --prune --force origin ${{github.sha}}
git checkout --force ${{github.sha}}
git log -1
- name: Run brew test-bot --only-cleanup-before
run: brew test-bot --only-cleanup-before
- name: Run brew test-bot --only-setup
run: brew test-bot --only-setup
- name: Run brew test-bot --only-cleanup-after
if: always()
run: brew test-bot --only-cleanup-after
- name: Cleanup
if: always()
run: |
find .
rm -rf *

41
.github/workflows/spdx.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: Update license data
on:
schedule:
- cron: '0 */12 * * *'
jobs:
spdx:
runs-on: ubuntu-latest
env:
HOMEBREW_NO_ANALYTICS: 1
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure Git
uses: Homebrew/actions/git-user-config@master
with:
username: BrewTestBot
- name: Setup Homebrew
run: |
HOMEBREW_REPOSITORY="$(brew --repo)"
rm -rf "$HOMEBREW_REPOSITORY"
ln -s "$GITHUB_WORKSPACE" "$HOMEBREW_REPOSITORY"
- name: Update license data
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd "$GITHUB_WORKSPACE/Library/Homebrew"
if brew update-license-data --commit --fail-if-not-changed; then
SPDX_VERSION=$(jq -er .licenseListVersion data/spdx.json)
if ! git ls-remote --exit-code --heads origin "spdx-$SPDX_VERSION"; then
git checkout -b "spdx-$SPDX_VERSION"
git push origin "spdx-$SPDX_VERSION"
hub pull-request -m "$(git log -1 --format='%s')"
fi
fi

View File

@ -62,12 +62,12 @@ jobs:
- name: Run brew doctor
run: |
# minimally fix brew doctor failures (a full clean takes ~5m)
if [ "$RUNNER_OS" = "Linux" ]; then
# Cleanup some Linux `brew doctor` failures
sudo rm -rf /usr/local/include/node/
else
# Link old gettext (otherwise `brew doctor` is sad)
brew link gettext
# link old formulae
brew link --overwrite --force gettext python@3.8
# remove deleted formula
brew uninstall --force python@2
@ -114,9 +114,6 @@ jobs:
- name: Run brew man
run: brew man --fail-if-changed
- name: Check for outdated license data
run: brew update-license-data --fail-if-changed
- name: Run brew tests
run: |
# brew tests doesn't like world writable directories

2
.gitignore vendored
View File

@ -85,6 +85,7 @@
**/vendor/bundle/ruby/*/gems/bundler-*/
**/vendor/bundle/ruby/*/gems/byebug-*/
**/vendor/bundle/ruby/*/gems/coderay-*/
**/vendor/bundle/ruby/*/gems/colorize-*/
**/vendor/bundle/ruby/*/gems/connection_pool-*/
**/vendor/bundle/ruby/*/gems/codecov-*/
**/vendor/bundle/ruby/*/gems/diff-lcs-*/
@ -129,7 +130,6 @@
**/vendor/bundle/ruby/*/gems/simplecov-*/
**/vendor/bundle/ruby/*/gems/simplecov-html-*/
**/vendor/bundle/ruby/*/gems/thor-*/
**/vendor/bundle/ruby/*/gems/url-*/
**/vendor/bundle/ruby/*/gems/unf_ext-*/
**/vendor/bundle/ruby/*/gems/unf-*/
**/vendor/bundle/ruby/*/gems/unicode-display_width-*/

View File

@ -9,10 +9,11 @@ GEM
zeitwerk (~> 2.2, >= 2.2.2)
ast (2.4.1)
byebug (11.1.3)
codecov (0.1.17)
codecov (0.2.2)
colorize
json
simplecov
url
colorize (0.8.1)
concurrent-ruby (1.1.6)
connection_pool (2.2.3)
diff-lcs (1.4.4)
@ -22,7 +23,7 @@ GEM
hpricot (0.8.6)
http-cookie (1.0.3)
domain_name (~> 0.5)
i18n (1.8.3)
i18n (1.8.4)
concurrent-ruby (~> 1.0)
json (2.3.1)
mechanize (2.7.6)
@ -80,7 +81,7 @@ GEM
rspec-support (3.9.3)
rspec-wait (0.0.9)
rspec (>= 3, < 4)
rubocop (0.87.0)
rubocop (0.88.0)
parallel (~> 1.10)
parser (>= 2.7.1.1)
rainbow (>= 2.2.2, < 4.0)
@ -89,12 +90,12 @@ GEM
rubocop-ast (>= 0.1.0, < 1.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-ast (0.1.0)
rubocop-ast (0.2.0)
parser (>= 2.7.0.1)
rubocop-performance (1.6.1)
rubocop (>= 0.71.0)
rubocop-rspec (1.41.0)
rubocop (>= 0.68.1)
rubocop-performance (1.7.1)
rubocop (>= 0.82.0)
rubocop-rspec (1.42.0)
rubocop (>= 0.87.0)
ruby-macho (2.2.0)
ruby-progressbar (1.10.1)
simplecov (0.18.5)
@ -108,9 +109,8 @@ GEM
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
url (0.3.2)
webrobots (0.1.2)
zeitwerk (2.3.1)
zeitwerk (2.4.0)
PLATFORMS
ruby

View File

@ -127,7 +127,7 @@ begin
ENV.delete("HOMEBREW_HELP") if help_flag
tap_commands = []
cgroup = Utils.popen_read("cat", "/proc/1/cgroup")
if !cgroup.include?("azpl_job") && !cgroup.include?("docker")
if %w[azpl_job actions_job docker garden kubepods].none? { |container| cgroup.include?(container) }
brew_uid = HOMEBREW_BREW_FILE.stat.uid
tap_commands += %W[/usr/bin/sudo -u ##{brew_uid}] if Process.uid.zero? && !brew_uid.zero?
end

View File

@ -1,7 +1,19 @@
HOMEBREW_PROCESSOR="$(uname -m)"
HOMEBREW_SYSTEM="$(uname -s)"
case "$HOMEBREW_SYSTEM" in
Darwin) HOMEBREW_MACOS="1" ;;
Linux) HOMEBREW_LINUX="1" ;;
esac
# Force UTF-8 to avoid encoding issues for users with broken locale settings.
if [[ "$(locale charmap 2>/dev/null)" != "UTF-8" ]]
then
export LC_ALL="en_US.UTF-8"
if [[ -n "$HOMEBREW_MACOS" ]]
then
export LC_ALL="en_US.UTF-8"
else
export LC_ALL="C.UTF-8"
fi
fi
# USER isn't always set so provide a fall back for `brew` and subprocesses.
@ -87,12 +99,6 @@ then
odie "Cowardly refusing to continue at this prefix: $HOMEBREW_PREFIX"
fi
HOMEBREW_SYSTEM="$(uname -s)"
case "$HOMEBREW_SYSTEM" in
Darwin) HOMEBREW_MACOS="1" ;;
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
@ -119,11 +125,9 @@ fi
if [[ -n "$HOMEBREW_MACOS" ]]
then
HOMEBREW_PROCESSOR="$(uname -p)"
HOMEBREW_PRODUCT="Homebrew"
HOMEBREW_SYSTEM="Macintosh"
# This is i386 even on x86_64 machines
[[ "$HOMEBREW_PROCESSOR" = "i386" ]] && HOMEBREW_PROCESSOR="Intel"
[[ "$HOMEBREW_PROCESSOR" = "x86_64" ]] && HOMEBREW_PROCESSOR="Intel"
HOMEBREW_MACOS_VERSION="$(/usr/bin/sw_vers -productVersion)"
HOMEBREW_OS_VERSION="macOS $HOMEBREW_MACOS_VERSION"
# Don't change this from Mac OS X to match what macOS itself does in Safari on 10.12
@ -166,7 +170,6 @@ then
HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH="1"
fi
else
HOMEBREW_PROCESSOR="$(uname -m)"
HOMEBREW_PRODUCT="${HOMEBREW_SYSTEM}brew"
[[ -n "$HOMEBREW_LINUX" ]] && HOMEBREW_OS_VERSION="$(lsb_release -sd 2>/dev/null)"
: "${HOMEBREW_OS_VERSION:=$(uname -r)}"
@ -271,6 +274,11 @@ export HOMEBREW_USER_AGENT
export HOMEBREW_USER_AGENT_CURL
export HOMEBREW_BOTTLE_DEFAULT_DOMAIN
if [[ -n "$HOMEBREW_DEVELOPER" ]] && [[ -z "$HOMEBREW_NO_PATCHELF_RB" ]]
then
export HOMEBREW_PATCHELF_RB="1"
fi
if [[ -n "$HOMEBREW_MACOS" && -x "/usr/bin/xcode-select" ]]
then
XCODE_SELECT_PATH=$('/usr/bin/xcode-select' --print-path 2>/dev/null)
@ -430,8 +438,8 @@ fi
check-run-command-as-root() {
[[ "$(id -u)" = 0 ]] || return
# Allow Azure Pipelines/Docker/Concourse/Kubernetes to do everything as root (as it's normal there)
[[ -f /proc/1/cgroup ]] && grep -E "azpl_job|docker|garden|kubepods" -q /proc/1/cgroup && return
# Allow Azure Pipelines/GitHub Actions/Docker/Concourse/Kubernetes to do everything as root (as it's normal there)
[[ -f /proc/1/cgroup ]] && grep -E "azpl_job|actions_job|docker|garden|kubepods" -q /proc/1/cgroup && return
# Homebrew Services may need `sudo` for system-wide daemons.
[[ "$HOMEBREW_COMMAND" = "services" ]] && return

View File

@ -208,11 +208,12 @@ rescue Exception => e # rubocop:disable Lint/RescueException
# BuildErrors are specific to build processes and not other
# children, which is why we create the necessary state here
# and not in Utils.safe_fork.
if error_hash["json_class"] == "BuildError"
case error_hash["json_class"]
when "BuildError"
error_hash["cmd"] = e.cmd
error_hash["args"] = e.args
error_hash["env"] = e.env
elsif error_hash["json_class"] == "ErrorDuringExecution"
when "ErrorDuringExecution"
error_hash["cmd"] = e.cmd
error_hash["status"] = e.status.exitstatus
error_hash["output"] = e.output

View File

@ -77,7 +77,7 @@ module Cask
Manpage,
PostflightBlock,
Zap,
].each_with_index.flat_map { |classes, i| [*classes].map { |c| [c, i] } }.to_h
].each_with_index.flat_map { |classes, i| Array(classes).map { |c| [c, i] } }.to_h
(@@sort_order[self.class] <=> @@sort_order[other.class]).to_i
end

View File

@ -34,7 +34,7 @@ module Cask
directives.assert_valid_keys!(*ORDERED_DIRECTIVES)
super(cask)
directives[:signal] = [*directives[:signal]].flatten.each_slice(2).to_a
directives[:signal] = Array(directives[:signal]).flatten.each_slice(2).to_a
@directives = directives
return unless directives.key?(:kext)
@ -49,7 +49,7 @@ module Cask
end
def summarize
to_h.flat_map { |key, val| [*val].map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ")
to_h.flat_map { |key, val| Array(val).map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ")
end
private

View File

@ -3,58 +3,69 @@
module Cask
class Cmd
class List < AbstractCommand
option "-1", :one, false
option "--versions", :versions, false
option "--full-name", :full_name, false
option "-1", :one, false
option "--versions", :versions, false
option "--full-name", :full_name, false
option "--json", :json, false
def run
args.any? ? list : list_installed
def self.usage
<<~EOS
`cask list`, `cask ls` [<options>] [<casks>]
-1 - Force output to be one entry per line.
This is the default when output is not to a terminal.
--versions - Show the version number for installed formulae, or only the specified
casks if <casks> are provided.
--full-name - Print casks with fully-qualified names.
--json - Print a JSON representation of <cask>. See the docs for examples of using the JSON
output: <https://docs.brew.sh/Querying-Brew>
List all installed casks.
If <casks> are provided, limit information to just those casks.
EOS
end
def list
def self.help
"lists installed Casks or the casks provided in the arguments"
end
def run
output = args.any? ? provided_list : Caskroom.casks
if json?
puts JSON.generate(output.map(&:to_h))
elsif one?
puts output.map(&:to_s)
elsif full_name?
puts output.map(&:full_name).sort(&tap_and_name_comparison)
elsif versions?
puts output.map(&self.class.method(:format_versioned))
elsif !output.empty? && args.any?
puts output.map(&self.class.method(:list_artifacts))
elsif !output.empty?
puts Formatter.columns(output.map(&:to_s))
end
end
def provided_list
casks.each do |cask|
raise CaskNotInstalledError, cask unless cask.installed?
if one?
puts cask.token
elsif versions?
puts self.class.format_versioned(cask)
else
cask = CaskLoader.load(cask.installed_caskfile)
self.class.list_artifacts(cask)
end
end
casks
end
def self.list_artifacts(cask)
cask.artifacts.group_by(&:class).each do |klass, artifacts|
next unless klass.respond_to?(:english_description)
ohai klass.english_description, artifacts.map(&:summarize_installed)
end
end
def list_installed
installed_casks = Caskroom.casks
if one?
puts installed_casks.map(&:to_s)
elsif versions?
puts installed_casks.map(&self.class.method(:format_versioned))
elsif full_name?
puts installed_casks.map(&:full_name).sort(&tap_and_name_comparison)
elsif !installed_casks.empty?
puts Formatter.columns(installed_casks.map(&:to_s))
return "==> #{klass.english_description}", artifacts.map(&:summarize_installed)
end
end
def self.format_versioned(cask)
cask.to_s.concat(cask.versions.map(&:to_s).join(" ").prepend(" "))
end
def self.help
"with no args, lists installed Casks; given installed Casks, lists staged files"
end
end
end
end

View File

@ -18,7 +18,7 @@ module Cask
def initialize(**pairs)
pairs.assert_valid_keys!(*VALID_KEYS)
super(pairs.transform_values { |v| Set.new([*v]) })
super(pairs.transform_values { |v| Set.new(Array(v)) })
self.default = Set.new
end

View File

@ -328,8 +328,12 @@ module Cask
def missing_cask_and_formula_dependencies
collect_cask_and_formula_dependencies.reject do |cask_or_formula|
(cask_or_formula.try(:installed?) || cask_or_formula.try(:any_version_installed?)) &&
(cask_or_formula.respond_to?(:opt_linked?) ? cask_or_formula.opt_linked? : true)
installed = if cask_or_formula.respond_to?(:any_version_installed?)
cask_or_formula.any_version_installed?
else
cask_or_formula.try(:installed?)
end
installed && (cask_or_formula.respond_to?(:opt_linked?) ? cask_or_formula.opt_linked? : true)
end
end

View File

@ -15,13 +15,21 @@ module CleanupRefinement
end
def nested_cache?
directory? && %w[cargo_cache go_cache glide_home java_cache npm_cache gclient_cache].include?(basename.to_s)
directory? && %w[
cargo_cache
go_cache
go_mod_cache
glide_home
java_cache
npm_cache
gclient_cache
].include?(basename.to_s)
end
def go_cache_directory?
# Go makes its cache contents read-only to ensure cache integrity,
# which makes sense but is something we need to undo for cleanup.
directory? && %w[go_cache].include?(basename.to_s)
directory? && %w[go_cache go_mod_cache].include?(basename.to_s)
end
def prune?(days)
@ -302,6 +310,7 @@ module Homebrew
end
def cleanup_path(path)
return unless path.exist?
return unless @cleaned_up_paths.add?(path)
disk_usage = path.disk_usage

View File

@ -213,10 +213,11 @@ module Homebrew
end
def min_named(count_or_type)
if count_or_type.is_a?(Integer)
case count_or_type
when Integer
@min_named_args = count_or_type
@min_named_type = nil
elsif count_or_type.is_a?(Symbol)
when Symbol
@min_named_args = 1
@min_named_type = count_or_type
else
@ -225,10 +226,11 @@ module Homebrew
end
def named(count_or_type)
if count_or_type.is_a?(Integer)
case count_or_type
when Integer
@max_named_args = @min_named_args = count_or_type
@min_named_type = nil
elsif count_or_type.is_a?(Symbol)
when Symbol
@max_named_args = @min_named_args = 1
@min_named_type = count_or_type
else

View File

@ -3,6 +3,7 @@
require "metafiles"
require "formula"
require "cli/parser"
require "cask/cmd"
module Homebrew
module_function
@ -31,6 +32,8 @@ module Homebrew
switch "--pinned",
description: "Show the versions of pinned formulae, or only the specified (pinned) "\
"formulae if <formula> are provided. See also `pin`, `unpin`."
switch "--cask",
description: "List casks"
# passed through to ls
switch "-1",
description: "Force output to be one entry per line. " \
@ -44,12 +47,15 @@ module Homebrew
description: "Sort by time modified, listing most recently modified first."
switch :verbose
switch :debug
["--unbrewed", "--multiple", "--pinned", "-l", "-r", "-t"].each { |flag| conflicts "--cask", flag }
end
end
def list
list_args.parse
return list_casks if args.cask?
return list_unbrewed if args.unbrewed?
# Unbrewed uses the PREFIX, which will exist
@ -150,6 +156,14 @@ module Homebrew
end
end
end
def list_casks
cask_list = Cask::Cmd::List.new args.named
cask_list.one = ARGV.include? "-1"
cask_list.versions = args.versions?
cask_list.full_name = args.full_name?
cask_list.run
end
end
class PrettyListing

View File

@ -6,8 +6,8 @@
#: 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
*/fish|fish)
case "$(/bin/ps -p $PPID -o comm=)" in
fish|-fish)
echo "set -gx HOMEBREW_PREFIX \"$HOMEBREW_PREFIX\";"
echo "set -gx HOMEBREW_CELLAR \"$HOMEBREW_CELLAR\";"
echo "set -gx HOMEBREW_REPOSITORY \"$HOMEBREW_REPOSITORY\";"
@ -15,7 +15,7 @@ homebrew-shellenv() {
echo "set -q MANPATH; or set MANPATH ''; set -gx MANPATH \"$HOMEBREW_PREFIX/share/man\" \$MANPATH;"
echo "set -q INFOPATH; or set INFOPATH ''; set -gx INFOPATH \"$HOMEBREW_PREFIX/share/info\" \$INFOPATH;"
;;
*/csh|csh|*/tcsh|tcsh)
csh|-csh|tcsh|-tcsh)
echo "setenv HOMEBREW_PREFIX $HOMEBREW_PREFIX;"
echo "setenv HOMEBREW_CELLAR $HOMEBREW_CELLAR;"
echo "setenv HOMEBREW_REPOSITORY $HOMEBREW_REPOSITORY;"
@ -29,7 +29,7 @@ homebrew-shellenv() {
echo "export HOMEBREW_REPOSITORY=\"$HOMEBREW_REPOSITORY\";"
echo "export PATH=\"$HOMEBREW_PREFIX/bin:$HOMEBREW_PREFIX/sbin\${PATH+:\$PATH}\";"
echo "export MANPATH=\"$HOMEBREW_PREFIX/share/man\${MANPATH+:\$MANPATH}:\";"
echo "export INFOPATH=\"$HOMEBREW_PREFIX/share/info:\${INFOPATH}\";"
echo "export INFOPATH=\"$HOMEBREW_PREFIX/share/info:\${INFOPATH:-}\";"
;;
esac
}

View File

@ -199,10 +199,11 @@ class Reporter
if paths.any? { |p| tap.cask_file?(p) }
# Currently only need to handle Cask deletion/migration.
if status == "D"
case status
when "D"
# Have a dedicated report array for deleted casks.
@report[:DC] << tap.formula_file_to_name(src)
elsif status == "M"
when "M"
# Report updated casks
@report[:MC] << tap.formula_file_to_name(src)
end

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
require "irb"
# @private
module IRB
@setup_done = false

View File

@ -231,11 +231,6 @@ module Homebrew
end
def audit_file
# TODO: check could be in RuboCop
if text.to_s.match?(/inreplace [^\n]* do [^\n]*\n[^\n]*\.gsub![^\n]*\n\ *end/m)
problem "'inreplace ... do' was used for a single substitution (use the non-block form instead)."
end
if formula.core_formula? && @versioned_formula
unversioned_formula = begin
# build this ourselves as we want e.g. homebrew/core to be present
@ -564,6 +559,7 @@ module Homebrew
_, user, repo = *regex.match(formula.stable.url) if formula.stable
_, user, repo = *regex.match(formula.homepage) unless user
_, user, repo = *regex.match(formula.head.url) if !user && formula.head
return if !user || !repo
repo.delete_suffix!(".git")
@ -576,13 +572,13 @@ module Homebrew
imagemagick@6
].freeze
THROTTLED_DENYLIST = {
"aws-sdk-cpp" => "10",
"awscli@1" => "10",
"balena-cli" => "10",
"gatsby-cli" => "10",
"quicktype" => "10",
"vim" => "50",
THROTTLED_FORMULAE = {
"aws-sdk-cpp" => 10,
"awscli@1" => 10,
"balena-cli" => 10,
"gatsby-cli" => 10,
"quicktype" => 10,
"vim" => 50,
}.freeze
UNSTABLE_ALLOWLIST = {
@ -611,7 +607,7 @@ module Homebrew
"libepoxy" => "1.5",
}.freeze
GITHUB_PRERELEASE_ALLOWLIST = %w[cake].freeze
GITHUB_PRERELEASE_ALLOWLIST = %w[].freeze
# version_prefix = stable_version_string.sub(/\d+$/, "")
# version_prefix = stable_version_string.split(".")[0..1].join(".")
@ -668,19 +664,10 @@ module Homebrew
problem "Formulae in homebrew/core should not have a `devel` spec" if formula.devel
if formula.head && @versioned_formula
head_spec_message = "Formulae should not have a `HEAD` spec"
head_spec_message = "Versioned formulae should not have a `HEAD` spec"
problem head_spec_message unless VERSIONED_HEAD_SPEC_ALLOWLIST.include?(formula.name)
end
THROTTLED_DENYLIST.each do |f, v|
next if formula.stable.nil?
version = formula.stable.version.to_s.split(".").last.to_i
if f == formula.name && version.modulo(v.to_i).nonzero?
problem "should only be updated every #{v} releases on multiples of #{v}"
end
end
stable = formula.stable
return unless stable
return unless stable.url
@ -691,6 +678,12 @@ module Homebrew
.split(".", 3)
.map(&:to_i)
formula_suffix = stable_version_string.split(".").last.to_i
throttled_rate = THROTTLED_FORMULAE[formula.name]
if throttled_rate && formula_suffix.modulo(throttled_rate).nonzero?
problem "should only be updated every #{throttled_rate} releases on multiples of #{throttled_rate}"
end
case (url = stable.url)
when /[\d._-](alpha|beta|rc\d)/
matched = Regexp.last_match(1)
@ -830,73 +823,6 @@ module Homebrew
end
end
def audit_lines
text.without_patch.split("\n").each_with_index do |line, lineno|
line_problems(line, lineno + 1)
end
end
def line_problems(line, _lineno)
# Check for string interpolation of single values.
if line =~ /(system|inreplace|gsub!|change_make_var!).*[ ,]"#\{([\w.]+)\}"/
# TODO: check could be in RuboCop
problem "Don't need to interpolate \"#{Regexp.last_match(2)}\" with #{Regexp.last_match(1)}"
end
# Check for string concatenation; prefer interpolation
if line =~ /(#\{\w+\s*\+\s*['"][^}]+\})/
# TODO: check could be in RuboCop
problem "Try not to concatenate paths in string interpolation:\n #{Regexp.last_match(1)}"
end
# Prefer formula path shortcuts in Pathname+
if line =~ %r{\(\s*(prefix\s*\+\s*(['"])(bin|include|libexec|lib|sbin|share|Frameworks)[/'"])}
# TODO: check could be in RuboCop
problem(
"\"(#{Regexp.last_match(1)}...#{Regexp.last_match(2)})\" should" \
" be \"(#{Regexp.last_match(3).downcase}+...)\"",
)
end
# TODO: check could be in RuboCop
problem "Use separate make calls" if line.include?("make && make")
if line =~ /JAVA_HOME/i &&
[formula.name, *formula.deps.map(&:name)].none? { |name| name.match?(/^openjdk(@|$)/) } &&
formula.requirements.none? { |req| req.is_a?(JavaRequirement) }
# TODO: check could be in RuboCop
problem "Use `depends_on :java` to set JAVA_HOME"
end
return unless @strict
# TODO: check could be in RuboCop
problem "`env :userpaths` in formulae is deprecated" if line.include?("env :userpaths")
# TODO: check could be in RuboCop
problem "`#{Regexp.last_match(1)}` is now unnecessary" if line =~ /(require ["']formula["'])/
if line.match?(%r{#\{share\}/#{Regexp.escape(formula.name)}[/'"]})
# TODO: check could be in RuboCop
problem "Use \#{pkgshare} instead of \#{share}/#{formula.name}"
end
if !@core_tap && line =~ /depends_on .+ if build\.with(out)?\?\(?["']\w+["']\)?/
# TODO: check could be in RuboCop
problem "`Use :optional` or `:recommended` instead of `#{Regexp.last_match(0)}`"
end
if line =~ %r{share(\s*[/+]\s*)(['"])#{Regexp.escape(formula.name)}(?:\2|/)}
# TODO: check could be in RuboCop
problem "Use pkgshare instead of (share#{Regexp.last_match(1)}\"#{formula.name}\")"
end
return unless @core_tap
# TODO: check could be in RuboCop
problem "`env :std` in homebrew/core formulae is deprecated" if line.include?("env :std")
end
def audit_reverse_migration
# Only enforce for new formula being re-added to core
return unless @strict

View File

@ -446,10 +446,10 @@ module Homebrew
first
elsif second.start_with?("/")
second
elsif cellars.include?(:any)
:any
elsif cellars.include?(:any_skip_relocation)
:any_skip_relocation
elsif cellars.include?("any")
"any"
elsif cellars.include?("any_skip_relocation")
"any_skip_relocation"
else
second
end

View File

@ -18,7 +18,11 @@ module Homebrew
be made if either or both values are not supplied by the user.
If a <tag> is specified, the Git commit <revision> corresponding to that tag
must also be specified.
should also be specified. A best effort to determine the <revision> will be made
if the value is not supplied by the user.
If a <version> is specified, a best effort to determine the <URL> and <SHA-256> or
the <tag> and <revision> will be made if both values are not supplied by the user.
*Note:* this command cannot be used to transition a formula from a
URL-and-SHA-256 style specification into a tag-and-revision style specification,
@ -58,8 +62,8 @@ module Homebrew
flag "--tag=",
description: "Specify the new git commit <tag> for the formula."
flag "--revision=",
required_for: "--tag=",
description: "Specify the new git commit <revision> corresponding to the specified <tag>."
depends_on: "--tag=",
description: "Specify the new git commit <revision> corresponding to the specified <tag>."
switch :force
switch :quiet
switch :verbose
@ -119,34 +123,14 @@ module Homebrew
formula = args.formulae.first
new_url = args.url
if new_url && !formula
# Split the new URL on / and find any formulae that have the same URL
# except for the last component, but don't try to match any more than the
# first five components since sometimes the last component isn't the only
# one to change.
new_url_split = new_url.split("/")
maximum_url_components_to_match = 5
components_to_match = [new_url_split.count - 1, maximum_url_components_to_match].min
base_url = new_url_split.first(components_to_match).join("/")
base_url = /#{Regexp.escape(base_url)}/
is_devel = args.devel?
guesses = []
Formula.each do |f|
if is_devel && f.devel && f.devel.url && f.devel.url.match(base_url)
guesses << f
elsif f.stable&.url && f.stable.url.match(base_url)
guesses << f
end
end
if guesses.count == 1
formula = guesses.shift
elsif guesses.count > 1
odie "Couldn't guess formula for sure; could be one of these:\n#{guesses.map(&:name).join(", ")}"
end
end
formula ||= determine_formula_from_url(new_url, args.devel?) if new_url
raise FormulaUnspecifiedError unless formula
tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula)
check_open_pull_requests(formula, tap_full_name)
new_version = args.version
check_all_pull_requests(formula, tap_full_name, version: new_version) if new_version
requested_spec, formula_spec = if args.devel?
devel_message = " (devel)"
@ -175,28 +159,44 @@ module Homebrew
new_url.sub "mirrors.ocf.berkeley.edu/debian", "mirrorservice.org/sites/ftp.debian.org/debian"
end
new_mirrors ||= [new_mirror] unless new_mirror.nil?
forced_version = args.version
old_url = formula_spec.url
old_tag = formula_spec.specs[:tag]
old_formula_version = formula_version(formula, requested_spec)
old_version = old_formula_version.to_s
forced_version = new_version.present?
new_url_hash = if new_url && new_hash
check_all_pull_requests(formula, tap_full_name, url: new_url) unless new_version
true
elsif new_tag && new_revision
check_all_pull_requests(formula, tap_full_name, url: old_url, tag: new_tag) unless new_version
false
elsif !hash_type
odie "#{formula}: no --tag=/--revision= arguments specified!"
elsif !new_url
odie "#{formula}: no --url= argument specified!"
else
resource = Resource.new { @url = new_url }
resource.download_strategy = DownloadStrategyDetector.detect_from_url(new_url)
resource.owner = Resource.new(formula.name)
if forced_version
if forced_version == resource.version
forced_version = nil
else
resource.version = forced_version
end
odie "#{formula}: no --tag= or --version= argument specified!" if !new_tag && !new_version
new_tag ||= old_tag.gsub(old_version, new_version)
if new_tag == old_tag
odie <<~EOS
You probably need to bump this formula manually since the new tag
and old tag are both #{new_tag}.
EOS
end
odie "No --version= argument specified!" unless resource.version
resource_path = resource.fetch
check_all_pull_requests(formula, tap_full_name, url: old_url, tag: new_tag) unless new_version
resource_path, forced_version = fetch_resource(formula, new_version, old_url, tag: new_tag)
new_revision = Utils.popen_read("git -C \"#{resource_path}\" rev-parse -q --verify HEAD")
new_revision = new_revision.strip
false
elsif !new_url && !new_version
odie "#{formula}: no --url= or --version= argument specified!"
else
new_url ||= old_url.gsub(old_version, new_version)
if new_url == old_url
odie <<~EOS
You probably need to bump this formula manually since the new URL
and old URL are both:
#{new_url}
EOS
end
check_all_pull_requests(formula, tap_full_name, url: new_url) unless new_version
resource_path, forced_version = fetch_resource(formula, new_version, new_url)
tar_file_extensions = %w[.tar .tb2 .tbz .tbz2 .tgz .tlz .txz .tZ]
if tar_file_extensions.any? { |extension| new_url.include? extension }
gnu_tar_gtar_path = HOMEBREW_PREFIX/"opt/gnu-tar/bin/gtar"
@ -212,8 +212,6 @@ module Homebrew
end
end
old_formula_version = formula_version(formula, requested_spec)
replacement_pairs = []
if requested_spec == :stable && formula.revision.nonzero?
replacement_pairs << [
@ -253,7 +251,7 @@ module Homebrew
]
end
backup_file = File.read(formula.path) unless args.dry_run?
old_contents = File.read(formula.path) unless args.dry_run?
if new_mirrors
replacement_pairs << [
@ -273,44 +271,46 @@ module Homebrew
]
end
if forced_version && forced_version != "0"
if requested_spec == :stable
if forced_version && new_version != "0"
case requested_spec
when :stable
replacement_pairs << if File.read(formula.path).include?("version \"#{old_formula_version}\"")
[
old_formula_version.to_s,
forced_version,
new_version,
]
elsif new_mirrors
[
/^( +)(mirror "#{Regexp.escape(new_mirrors.last)}"\n)/m,
"\\1\\2\\1version \"#{forced_version}\"\n",
"\\1\\2\\1version \"#{new_version}\"\n",
]
else
[
/^( +)(url "#{Regexp.escape(new_url)}"\n)/m,
"\\1\\2\\1version \"#{forced_version}\"\n",
"\\1\\2\\1version \"#{new_version}\"\n",
]
end
elsif requested_spec == :devel
when :devel
replacement_pairs << [
/( devel do.+?version ")#{old_formula_version}("\n.+?end\n)/m,
"\\1#{forced_version}\\2",
"\\1#{new_version}\\2",
]
end
elsif forced_version && forced_version == "0"
if requested_spec == :stable
elsif forced_version && new_version == "0"
case requested_spec
when :stable
replacement_pairs << [
/^ version "[\w.\-+]+"\n/m,
"",
]
elsif requested_spec == :devel
when :devel
replacement_pairs << [
/( devel do.+?)^ +version "[^\n]+"\n(.+?end\n)/m,
"\\1\\2",
]
end
end
new_contents = inreplace_pairs(formula.path, replacement_pairs)
new_contents = inreplace_pairs(formula.path, replacement_pairs.uniq)
new_formula_version = formula_version(formula, requested_spec, new_contents)
@ -328,13 +328,13 @@ module Homebrew
end
if new_formula_version < old_formula_version
formula.path.atomic_write(backup_file) unless args.dry_run?
formula.path.atomic_write(old_contents) unless args.dry_run?
odie <<~EOS
You probably need to bump this formula manually since changing the
version from #{old_formula_version} to #{new_formula_version} would be a downgrade.
EOS
elsif new_formula_version == old_formula_version
formula.path.atomic_write(backup_file) unless args.dry_run?
formula.path.atomic_write(old_contents) unless args.dry_run?
odie <<~EOS
You probably need to bump this formula manually since the new version
and old version are both #{new_formula_version}.
@ -347,7 +347,7 @@ module Homebrew
alias_rename.map! { |a| formula.tap.alias_dir/a }
end
run_audit(formula, alias_rename, backup_file)
run_audit(formula, alias_rename, old_contents)
formula.path.parent.cd do
branch = "#{formula.name}-#{new_formula_version}"
@ -372,7 +372,7 @@ module Homebrew
remote_url = Utils.popen_read("git remote get-url --push origin").chomp
username = formula.tap.user
else
remote_url, username = forked_repo_info(formula, tap_full_name, backup_file)
remote_url, username = forked_repo_info(formula, tap_full_name, old_contents)
end
safe_system "git", "fetch", "--unshallow", "origin" if shallow
@ -411,10 +411,44 @@ module Homebrew
end
end
def forked_repo_info(formula, tap_full_name, backup_file)
def determine_formula_from_url(url, is_devel)
# Split the new URL on / and find any formulae that have the same URL
# except for the last component, but don't try to match any more than the
# first five components since sometimes the last component isn't the only
# one to change.
url_split = url.split("/")
maximum_url_components_to_match = 5
components_to_match = [url_split.count - 1, maximum_url_components_to_match].min
base_url = url_split.first(components_to_match).join("/")
base_url = /#{Regexp.escape(base_url)}/
guesses = []
Formula.each do |f|
if is_devel && f.devel && f.devel.url && f.devel.url.match(base_url)
guesses << f
elsif f.stable&.url && f.stable.url.match(base_url)
guesses << f
end
end
return guesses.shift if guesses.count == 1
return unless guesses.count > 1
odie "Couldn't guess formula for sure; could be one of these:\n#{guesses.map(&:name).join(", ")}"
end
def fetch_resource(formula, new_version, url, **specs)
resource = Resource.new
resource.url(url, specs)
resource.owner = Resource.new(formula.name)
forced_version = new_version && new_version != resource.version
resource.version = new_version if forced_version
odie "No --version= argument specified!" unless resource.version
[resource.fetch, forced_version]
end
def forked_repo_info(formula, tap_full_name, old_contents)
response = GitHub.create_fork(tap_full_name)
rescue GitHub::AuthenticationFailedError, *GitHub.api_errors => e
formula.path.atomic_write(backup_file)
formula.path.atomic_write(old_contents)
odie "Unable to fork: #{e.message}!"
else
# GitHub API responds immediately but fork takes a few seconds to be ready.
@ -503,7 +537,7 @@ module Homebrew
[versioned_alias, "#{name}@#{new_alias_version}"]
end
def run_audit(formula, alias_rename, backup_file)
def run_audit(formula, alias_rename, old_contents)
if args.dry_run?
if args.no_audit?
ohai "Skipping `brew audit`"
@ -527,7 +561,7 @@ module Homebrew
end
return unless failed_audit
formula.path.atomic_write(backup_file)
formula.path.atomic_write(old_contents)
FileUtils.mv alias_rename.last, alias_rename.first if alias_rename.present?
odie "`brew audit` failed!"
end

View File

@ -42,7 +42,12 @@ module Homebrew
[checksum.hash_type, checksum.hexdigest]
end
old = if formula.path.read.include?("stable do\n")
old = if formula.license
# insert replacement revision after license
<<~EOS
license "#{formula.license}"
EOS
elsif formula.path.read.include?("stable do\n")
# insert replacement revision after homepage
<<~EOS
homepage "#{formula.homepage}"

View File

@ -29,6 +29,8 @@ module Homebrew
description: "Create a basic template for a Go build."
switch "--meson",
description: "Create a basic template for a Meson-style build."
switch "--node",
description: "Create a basic template for a Node build."
switch "--perl",
description: "Create a basic template for a Perl build."
switch "--python",
@ -54,7 +56,7 @@ module Homebrew
switch :force
switch :verbose
switch :debug
conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--perl", "--python", "--rust"
conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", "--perl", "--python", "--rust"
named 1
end
end
@ -92,6 +94,8 @@ module Homebrew
:crystal
elsif args.go?
:go
elsif args.node?
:node
elsif args.perl?
:perl
elsif args.python?

View File

@ -124,10 +124,11 @@ module Homebrew
ronn.close_write
ronn_output = ronn.read
odie "Got no output from ronn!" if ronn_output.blank?
if format_flag == "--markdown"
case format_flag
when "--markdown"
ronn_output = ronn_output.gsub(%r{<var>(.*?)</var>}, "*`\\1`*")
.gsub(/\n\n\n+/, "\n\n")
elsif format_flag == "--roff"
when "--roff"
ronn_output = ronn_output.gsub(%r{<code>(.*?)</code>}, "\\fB\\1\\fR")
.gsub(%r{<var>(.*?)</var>}, "\\fI\\1\\fR")
.gsub(/(^\[?\\fB.+): /, "\\1\n ")

View File

@ -1,28 +1,26 @@
# frozen_string_literal: true
require "commands"
require "cli/parser"
require "json"
require "net/http"
require "open-uri"
require "utils/github"
module Homebrew
module_function
SPDX_PATH = (HOMEBREW_LIBRARY_PATH/"data/spdx.json").freeze
SPDX_DATA_URL = "https://raw.githubusercontent.com/spdx/license-list-data/HEAD/json/licenses.json"
SPDX_API_URL = "https://api.github.com/repos/spdx/license-list-data/releases/latest"
def update_license_data_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`update_license_data` <cmd>
`update-license-data` [<options>]
Update SPDX license data in the Homebrew repository.
EOS
switch "--fail-if-changed",
description: "Return a failing status code if current license data's version is different from " \
switch "--fail-if-not-changed",
description: "Return a failing status code if current license data's version is the same as " \
"the upstream. This can be used to notify CI when the SPDX license data is out of date."
switch "--commit",
description: "Commit changes to the SPDX license data."
max_named 0
end
end
@ -30,10 +28,18 @@ module Homebrew
def update_license_data
update_license_data_args.parse
ohai "Updating SPDX license data..."
curl_download(SPDX_DATA_URL, to: SPDX_PATH, partial: false)
return unless args.fail_if_changed?
latest_tag = GitHub.open_api(SPDX_API_URL)["tag_name"]
data_url = "https://raw.githubusercontent.com/spdx/license-list-data/#{latest_tag}/json/licenses.json"
curl_download(data_url, to: SPDX_PATH, partial: false)
safe_system "git", "diff", "--stat", "--exit-code", SPDX_PATH
Homebrew.failed = system("git", "diff", "--stat", "--exit-code", SPDX_PATH) if args.fail_if_not_changed?
return unless args.commit?
ohai "git add"
safe_system "git", "add", SPDX_PATH
ohai "git commit"
system "git", "commit", "--message", "data/spdx.json: update to #{latest_tag}"
end
end

View File

@ -392,11 +392,11 @@ module Homebrew
message = inject_file_list conflicts, <<~EOS
/usr/bin occurs before #{HOMEBREW_PREFIX}/bin
This means that system-provided programs will be used instead of those
provided by Homebrew. The following tools exist at both paths:
Consider setting your PATH so that #{HOMEBREW_PREFIX}/bin
occurs before /usr/bin. Here is a one-liner:
provided by Homebrew. Consider setting your PATH so that
#{HOMEBREW_PREFIX}/bin occurs before /usr/bin. Here is a one-liner:
#{Utils::Shell.prepend_path_in_profile("#{HOMEBREW_PREFIX}/bin")}
The following tools exist at both paths:
EOS
end
end
@ -561,7 +561,7 @@ module Homebrew
return if !Utils.git_available? || !(coretap_path/".git").exist?
branch = coretap_path.git_branch
return if branch.nil? || branch =~ /master/
return if branch.blank? || branch.include?("master")
<<~EOS
#{CoreTap.instance.full_name} is not on the master branch.

View File

@ -111,6 +111,10 @@ module Homebrew
description: "Output this many lines of output on formula `system` failures.",
default: 15,
},
HOMEBREW_FORBIDDEN_LICENSES: {
description: "A space-separated list of licenses. Homebrew will refuse to install a " \
"formula if that formula or any of its dependencies has a license on this list.",
},
HOMEBREW_FORCE_BREWED_CURL: {
description: "If set, always use a Homebrew-installed `curl`(1) rather than the system version. " \
"Automatically set if the system version of `curl` is too old.",

View File

@ -320,6 +320,18 @@ class FormulaConflictError < RuntimeError
end
end
class FormulaUnknownPythonError < RuntimeError
def initialize(formula)
super <<~EOS
The version of Python to use with the virtualenv in the `#{formula.full_name}` formula
cannot be guessed automatically because a recognised Python dependency could not be found.
If you are using a non-standard Python depedency, please add `:using => "python@x.y"` to
`virtualenv_install_with_resources` to resolve the issue manually.
EOS
end
end
class FormulaAmbiguousPythonError < RuntimeError
def initialize(formula)
super <<~EOS
@ -494,7 +506,7 @@ class CurlDownloadStrategyError < RuntimeError
end
end
# Raised by {#safe_system} in `utils.rb`.
# Raised by {Kernel#safe_system} in `utils.rb`.
class ErrorDuringExecution < RuntimeError
attr_reader :cmd, :status, :output
@ -512,7 +524,7 @@ class ErrorDuringExecution < RuntimeError
redacted_cmd = redact_secrets(cmd.shelljoin.gsub('\=', "="), secrets)
s = +"Failure while executing; `#{redacted_cmd}` exited with #{exitstatus}."
unless [*output].empty?
if Array(output).present?
format_output_line = lambda do |type_line|
type, line = *type_line
if type == :stderr
@ -531,7 +543,7 @@ class ErrorDuringExecution < RuntimeError
end
def stderr
[*output].select { |type,| type == :stderr }.map(&:last).join
Array(output).select { |type,| type == :stderr }.map(&:last).join
end
end

View File

@ -7,11 +7,38 @@ class Formula
"#{name}.so#{"." unless version.nil?}#{version}"
end
undef allowed_missing_lib?
def allowed_missing_lib?(lib)
# lib: Full path to the missing library
# Ex.: /home/linuxbrew/.linuxbrew/lib/libsomething.so.1
# x - Name of or a pattern for a library, linkage to which is allowed to be missing.
# Ex. 1: "libONE.so.1"
# Ex. 2: %r{(libONE|libTWO)\.so}
self.class.allowed_missing_libraries.any? do |x|
case x
when Regexp
x.match? lib
when String
lib.include? x
end
end
end
class << self
undef on_linux
def on_linux(&_block)
yield
end
def ignore_missing_libraries(*libs)
libs.flatten!
allowed_missing_libraries.merge(libs)
end
# @private
def allowed_missing_libraries
@allowed_missing_libraries ||= Set.new
end
end
end

View File

@ -191,7 +191,8 @@ module Homebrew
def check_xcode_license_approved
# If the user installs Xcode-only, they have to approve the
# license or no "xc*" tool will work.
return unless `/usr/bin/xcrun clang 2>&1` =~ /license/ && !$CHILD_STATUS.success?
return unless `/usr/bin/xcrun clang 2>&1`.include?("license")
return if $CHILD_STATUS.success?
<<~EOS
You have not agreed to the Xcode license.

View File

@ -2,7 +2,9 @@
module Hardware
def self.oldest_cpu(version = MacOS.version)
if version >= :mojave
if CPU.arch == :arm64
:arm_vortex_tempest
elsif version >= :mojave
:nehalem
else
generic_oldest_cpu

View File

@ -6,9 +6,11 @@ module Utils
undef tag
def tag
tag = MacOS.version.to_sym
tag = "#{tag}_arm".to_sym if Hardware::CPU.arm?
tag
if Hardware::CPU.intel?
MacOS.version.to_sym
else
"#{Hardware::CPU.arch}_#{MacOS.version.to_sym}".to_sym
end
end
end

View File

@ -352,6 +352,8 @@ class Formula
delegate desc: :"self.class"
# The SPDX ID of the software license.
# @method license
# @see .license=
delegate license: :"self.class"
# The homepage for the software.
@ -495,6 +497,10 @@ class Formula
# The link status symlink directory for this {Formula}.
# You probably want {#opt_prefix} instead.
def linked_keg
linked_keg = possible_names.map { |name| HOMEBREW_LINKED_KEGS/name }
.find(&:directory?)
return linked_keg if linked_keg.present?
HOMEBREW_LINKED_KEGS/name
end
@ -598,7 +604,10 @@ class Formula
# All currently installed prefix directories.
# @private
def installed_prefixes
rack.directory? ? rack.subdirs.sort : []
possible_names.map { |name| HOMEBREW_CELLAR/name }
.select(&:directory?)
.flat_map(&:subdirs)
.sort_by(&:basename)
end
# All currently installed kegs.
@ -934,14 +943,10 @@ class Formula
end
# @private
def plist_manual
self.class.plist_manual
end
delegate plist_manual: :"self.class"
# @private
def plist_startup
self.class.plist_startup
end
delegate plist_startup: :"self.class"
# A stable path for this formula, when installed. Contains the formula name
# but no version number. Only the active version will be linked here if
@ -1001,9 +1006,7 @@ class Formula
end
# @private
def pour_bottle_check_unsatisfied_reason
self.class.pour_bottle_check_unsatisfied_reason
end
delegate pour_bottle_check_unsatisfied_reason: :"self.class"
# Can be overridden to run commands on both source and bottle installation.
def post_install; end
@ -1073,9 +1076,7 @@ class Formula
end
# @private
def keg_only_reason
self.class.keg_only_reason
end
delegate keg_only_reason: :"self.class"
# sometimes the formula cleaner breaks things
# skip cleaning paths in a formula with a class method like this:
@ -1119,7 +1120,7 @@ class Formula
return false # this keg belongs to another formula
else
# this keg belongs to another unrelated formula
return false unless (Array(f.aliases) + Array(f.oldname)).include?(keg.name)
return false unless f.possible_names.include?(keg.name)
end
end
to_check = path.relative_path_from(HOMEBREW_PREFIX).to_s
@ -1130,19 +1131,24 @@ class Formula
end
end
# Whether this {Formula} is deprecated (i.e. warns on installation).
# Whether this {Formula} is allowed to have a broken linkage to specified library.
# Defaults to false.
# @return [Boolean]
def deprecated?
self.class.deprecated?
def allowed_missing_lib?(*)
false
end
# Whether this {Formula} is deprecated (i.e. warns on installation).
# Defaults to false.
# @method deprecated?
# @return [Boolean]
delegate deprecated?: :"self.class"
# Whether this {Formula} is disabled (i.e. cannot be installed).
# Defaults to false.
# @method disabled?
# @return [Boolean]
def disabled?
self.class.disabled?
end
delegate disabled?: :"self.class"
def skip_cxxstdlib_check?
false
@ -1305,29 +1311,19 @@ class Formula
end
# @private
def pinnable?
@pin.pinnable?
end
delegate pinnable?: :@pin
# @private
def pinned?
@pin.pinned?
end
delegate pinned?: :@pin
# @private
def pinned_version
@pin.pinned_version
end
delegate pinned_version: :@pin
# @private
def pin
@pin.pin
end
delegate pin: :@pin
# @private
def unpin
@pin.unpin
end
delegate unpin: :@pin
# @private
def ==(other)
@ -1349,6 +1345,11 @@ class Formula
name <=> other.name
end
# @private
def possible_names
[name, oldname, *aliases].compact
end
def to_s
name
end
@ -1408,7 +1409,7 @@ class Formula
# Standard parameters for meson builds.
def std_meson_args
["--prefix=#{prefix}", "--libdir=#{lib}"]
["--prefix=#{prefix}", "--libdir=#{lib}", "--buildtype=release"]
end
def shared_library(name, version = nil)
@ -1577,14 +1578,10 @@ class Formula
end
# @private
def env
self.class.env
end
delegate env: :"self.class"
# @private
def conflicts
self.class.conflicts
end
delegate conflicts: :"self.class"
# Returns a list of Dependency objects in an installable order, which
# means if a depends on b then b will be ordered before a in this list
@ -1606,8 +1603,8 @@ class Formula
Formula.cache[:opt_or_installed_prefix_keg] ||= {}
Formula.cache[:opt_or_installed_prefix_keg][name] ||= if optlinked? && opt_prefix.exist?
Keg.new(opt_prefix)
elsif installed_prefix.directory?
Keg.new(installed_prefix)
elsif (latest_installed_prefix = installed_prefixes.last)
Keg.new(latest_installed_prefix)
end
end
@ -1775,10 +1772,9 @@ class Formula
}
end
installed_kegs.each do |keg|
hsh["installed"] = installed_kegs.sort_by(&:version).map do |keg|
tab = Tab.for_keg keg
hsh["installed"] << {
{
"version" => keg.version.to_s,
"used_options" => tab.used_options.as_flags,
"built_as_bottle" => tab.built_as_bottle,
@ -1789,8 +1785,6 @@ class Formula
}
end
hsh["installed"] = hsh["installed"].sort_by { |i| Version.create(i["version"]) }
hsh
end
@ -1809,17 +1803,13 @@ class Formula
@prefix_returns_versioned_prefix = true
test_env = {
CURL_HOME: ENV["CURL_HOME"] || ENV["HOME"],
TMPDIR: HOMEBREW_TEMP,
TEMP: HOMEBREW_TEMP,
TMP: HOMEBREW_TEMP,
TERM: "dumb",
PATH: PATH.new(ENV["PATH"], HOMEBREW_PREFIX/"bin"),
HOMEBREW_PATH: nil,
_JAVA_OPTIONS: "#{ENV["_JAVA_OPTIONS"]&.+(" ")}-Duser.home=#{HOMEBREW_CACHE}/java_cache",
GOCACHE: "#{HOMEBREW_CACHE}/go_cache",
CARGO_HOME: "#{HOMEBREW_CACHE}/cargo_cache",
}
}.merge(common_stage_test_env)
ENV.clear_sensitive_environment!
Utils.set_git_name_email!
@ -2140,6 +2130,17 @@ class Formula
exit! 1 # never gets here unless exec threw or failed
end
# Common environment variables used at both build and test time
def common_stage_test_env
{
_JAVA_OPTIONS: "#{ENV["_JAVA_OPTIONS"]&.+(" ")}-Duser.home=#{HOMEBREW_CACHE}/java_cache",
GOCACHE: "#{HOMEBREW_CACHE}/go_cache",
GOPATH: "#{HOMEBREW_CACHE}/go_mod_cache",
CARGO_HOME: "#{HOMEBREW_CACHE}/cargo_cache",
CURL_HOME: ENV["CURL_HOME"] || ENV["HOME"],
}
end
def stage
active_spec.stage do |staging|
@source_modified_time = active_spec.source_modified_time
@ -2153,12 +2154,7 @@ class Formula
unless Homebrew.args.interactive?
stage_env[:HOME] = env_home
stage_env[:_JAVA_OPTIONS] =
"#{ENV["_JAVA_OPTIONS"]&.+(" ")}-Duser.home=#{HOMEBREW_CACHE}/java_cache"
stage_env[:GOCACHE] = "#{HOMEBREW_CACHE}/go_cache"
stage_env[:GOPATH] = "#{HOMEBREW_CACHE}/go_mod_cache"
stage_env[:CARGO_HOME] = "#{HOMEBREW_CACHE}/cargo_cache"
stage_env[:CURL_HOME] = ENV["CURL_HOME"] || ENV["HOME"]
stage_env.merge!(common_stage_test_env)
end
setup_home env_home

View File

@ -84,6 +84,10 @@ module Homebrew
# Documentation: https://docs.brew.sh/Formula-Cookbook
# https://rubydoc.brew.sh/Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
<% if mode == :node %>
require "language/node"
<% end %>
class #{Formulary.class_s(name)} < Formula
<% if mode == :python %>
include Language::Python::Virtualenv
@ -91,9 +95,7 @@ module Homebrew
<% end %>
desc "#{desc}"
homepage "#{homepage}"
<% if head? %>
head "#{url}"
<% else %>
<% unless head? %>
url "#{url}"
<% unless version.nil? or version.detected_from_url? %>
version "#{version}"
@ -101,6 +103,9 @@ module Homebrew
sha256 "#{sha256}"
<% end %>
license "#{license}"
<% if head? %>
head "#{url}"
<% end %>
<% if mode == :cmake %>
depends_on "cmake" => :build
@ -111,6 +116,8 @@ module Homebrew
<% elsif mode == :meson %>
depends_on "meson" => :build
depends_on "ninja" => :build
<% elsif mode == :node %>
depends_on "node"
<% elsif mode == :perl %>
uses_from_macos "perl"
<% elsif mode == :python %>
@ -152,6 +159,9 @@ module Homebrew
system "ninja", "-v"
system "ninja", "install", "-v"
end
<% elsif mode == :node %>
system "npm", "install", *Language::Node.std_npm_install_args(libexec)
bin.install_symlink Dir["\#{libexec}/bin/*"]
<% elsif mode == :perl %>
ENV.prepend_create_path "PERL5LIB", libexec/"lib/perl5"
ENV.prepend_path "PERL5LIB", libexec/"lib"

View File

@ -17,6 +17,7 @@ require "linkage_checker"
require "install"
require "messages"
require "cask/cask_loader"
require "cmd/install"
require "find"
class FormulaInstaller
@ -148,6 +149,8 @@ class FormulaInstaller
def prelude
Tab.clear_cache
verify_deps_exist unless ignore_deps?
forbidden_license_check
check_install_sanity
end
@ -857,7 +860,7 @@ class FormulaInstaller
if formula.link_overwrite?(conflict_file) && !link_overwrite_backup.key?(conflict_file)
backup_file = backup_dir/conflict_file.relative_path_from(HOMEBREW_PREFIX).to_s
backup_file.parent.mkpath
conflict_file.rename backup_file
FileUtils.mv conflict_file, backup_file
link_overwrite_backup[conflict_file] = backup_file
retry
end
@ -889,7 +892,7 @@ class FormulaInstaller
keg.unlink
link_overwrite_backup.each do |origin, backup|
origin.parent.mkpath
backup.rename origin
FileUtils.mv backup, origin
end
end
Homebrew.failed = true
@ -1102,4 +1105,27 @@ class FormulaInstaller
$stderr.puts @requirement_messages
end
def forbidden_license_check
forbidden_licenses = Homebrew::EnvConfig.forbidden_licenses.to_s.split(" ")
return if forbidden_licenses.blank?
compute_dependencies.each do |dep, _|
next if @ignore_deps
dep_f = dep.to_formula
next unless forbidden_licenses.include? dep_f.license
raise CannotInstallFormulaError, <<~EOS
The installation of #{formula.name} has a dependency on #{dep.name} with a forbidden license #{dep_f.license}.
EOS
end
return if @only_deps
return unless forbidden_licenses.include? formula.license
raise CannotInstallFormulaError, <<~EOS
#{formula.name} has a forbidden license #{formula.license}.
EOS
end
end

View File

@ -12,14 +12,16 @@ module Hardware
class << self
def optimization_flags
@optimization_flags ||= {
native: arch_flag("native"),
nehalem: "-march=nehalem",
core2: "-march=core2",
core: "-march=prescott",
armv6: "-march=armv6",
armv8: "-march=armv8-a",
ppc64: "-mcpu=powerpc64",
ppc64le: "-mcpu=powerpc64le",
native: arch_flag("native"),
nehalem: "-march=nehalem",
sandybridge: "-march=sandybridge",
core2: "-march=core2",
core: "-march=prescott",
arm_vortex_tempest: "",
armv6: "-march=armv6",
armv8: "-march=armv8-a",
ppc64: "-mcpu=powerpc64",
ppc64le: "-mcpu=powerpc64le",
}.freeze
end
alias generic_optimization_flags optimization_flags

View File

@ -195,7 +195,7 @@ class Keg
def initialize(path)
path = path.resolved_path if path.to_s.start_with?("#{HOMEBREW_PREFIX}/opt/")
raise "#{path} is not a valid keg" unless path.parent.parent.realpath == HOMEBREW_CELLAR.realpath
raise "#{path} is not a valid keg" if path.parent.parent.realpath != HOMEBREW_CELLAR.realpath
raise "#{path} is not a directory" unless path.directory?
@path = path
@ -255,6 +255,7 @@ class Keg
def remove_old_aliases
opt = opt_record.parent
linkedkegs = linked_keg_record.parent
tap = begin
to_formula.tap
@ -272,24 +273,28 @@ class Keg
# versioned aliases are handled below
next if a.match?(/.+@./)
alias_symlink = opt/a
if alias_symlink.symlink? && alias_symlink.exist?
alias_symlink.delete if alias_symlink.realpath == opt_record.realpath
elsif alias_symlink.symlink? || alias_symlink.exist?
alias_symlink.delete
alias_opt_symlink = opt/a
if alias_opt_symlink.symlink? && alias_opt_symlink.exist?
alias_opt_symlink.delete if alias_opt_symlink.realpath == opt_record.realpath
elsif alias_opt_symlink.symlink? || alias_opt_symlink.exist?
alias_opt_symlink.delete
end
alias_linkedkegs_symlink = linkedkegs/a
alias_linkedkegs_symlink.delete if alias_linkedkegs_symlink.symlink? || alias_linkedkegs_symlink.exist?
end
Pathname.glob("#{opt_record}@*").each do |a|
a = a.basename.to_s
next if aliases.include?(a)
alias_symlink = opt/a
if alias_symlink.symlink? && alias_symlink.exist?
next if rack != alias_symlink.realpath.parent
alias_opt_symlink = opt/a
if alias_opt_symlink.symlink? && alias_opt_symlink.exist?
alias_opt_symlink.delete if rack == alias_opt_symlink.realpath.parent
end
alias_symlink.delete
alias_linkedkegs_symlink = linkedkegs/a
alias_linkedkegs_symlink.delete if alias_linkedkegs_symlink.symlink? || alias_linkedkegs_symlink.exist?
end
end
@ -322,9 +327,9 @@ class Keg
dirs = []
KEG_LINK_DIRECTORIES.map { |d| path/d }.each do |dir|
next unless dir.exist?
keg_directories = KEG_LINK_DIRECTORIES.map { |d| path/d }
.select(&:exist?)
keg_directories.each do |dir|
dir.find do |src|
dst = HOMEBREW_PREFIX + src.relative_path_from(path)
dst.extend(ObserverPathnameExtension)
@ -332,7 +337,8 @@ class Keg
dirs << dst if dst.directory? && !dst.symlink?
# check whether the file to be unlinked is from the current keg first
next unless dst.symlink? && src == dst.resolved_path
next unless dst.symlink?
next if src != dst.resolved_path
if mode.dry_run
puts dst
@ -509,7 +515,7 @@ class Keg
def remove_oldname_opt_record
return unless oldname_opt_record
return unless oldname_opt_record.resolved_path == path
return if oldname_opt_record.resolved_path != path
@oldname_opt_record.unlink
@oldname_opt_record.parent.rmdir_if_possible

View File

@ -27,7 +27,7 @@ module Language
f = find_openjdk_formula(version)
return f.opt_libexec if f
req = JavaRequirement.new [*version]
req = JavaRequirement.new Array(version)
raise UnsatisfiedRequirements, req.message unless req.satisfied?
req.java_home

View File

@ -180,8 +180,9 @@ module Language
def virtualenv_install_with_resources(options = {})
python = options[:using]
if python.nil?
pythons = %w[python python3 python@3 python@3.8 pypy pypy3]
pythons = %w[python python3 python@3 python@3.7 python@3.8 pypy pypy3]
wanted = pythons.select { |py| needs_python?(py) }
raise FormulaUnknownPythonError, self if wanted.empty?
raise FormulaAmbiguousPythonError, self if wanted.size > 1
python = wanted.first
@ -261,14 +262,14 @@ module Language
# the contents of a `requirements.txt`.
# @return [void]
def pip_install(targets)
targets = [targets] unless targets.is_a? Array
targets = Array(targets)
targets.each do |t|
if t.respond_to? :stage
next if t.name == "homebrew-virtualenv"
t.stage { do_install Pathname.pwd }
else
t = t.lines.map(&:strip) if t.respond_to?(:lines) && t =~ /\n/
t = t.lines.map(&:strip) if t.respond_to?(:lines) && t.include?("\n")
do_install t
end
end
@ -291,7 +292,7 @@ module Language
private
def do_install(targets)
targets = [targets] unless targets.is_a? Array
targets = Array(targets)
@formula.system @venv_root/"bin/pip", "install",
"-v", "--no-deps", "--no-binary", ":all:",
"--ignore-installed", *targets

View File

@ -55,18 +55,35 @@ class LinkageChecker
end
def display_test_output(puts_output: true)
display_items "Missing libraries", @broken_dylibs, puts_output: puts_output
display_items "Missing libraries", broken_dylibs_with_expectations, puts_output: puts_output
display_items "Broken dependencies", @broken_deps, puts_output: puts_output
display_items "Unwanted system libraries", @unwanted_system_dylibs, puts_output: puts_output
display_items "Conflicting libraries", @version_conflict_deps, puts_output: puts_output
puts "No broken library linkage" unless broken_library_linkage?
if @broken_dylibs.empty?
puts "No broken library linkage detected"
elsif unexpected_broken_libs.empty?
puts "No unexpected broken library linkage detected."
else
puts "Broken library linkage detected"
end
end
def broken_library_linkage?
!@broken_dylibs.empty? ||
!@broken_deps.empty? ||
!@unwanted_system_dylibs.empty? ||
!@version_conflict_deps.empty?
issues = [@broken_deps, @unwanted_system_dylibs, @version_conflict_deps]
[issues, unexpected_broken_libs].flatten.any?(&:present?)
end
def unexpected_broken_libs
@broken_dylibs.reject { |lib| @formula.allowed_missing_lib? lib }
end
def broken_dylibs_with_expectations
output = {}
@broken_dylibs.each do |lib|
output[lib] = (unexpected_broken_libs.include? lib) ? ["unexpected"] : ["expected"]
end
output
end
private

View File

@ -42,7 +42,7 @@ module OS
end
def languages
@languages ||= [*ENV["LANG"]&.slice(/[a-z]+/)].uniq
@languages ||= Array(ENV["LANG"]&.slice(/[a-z]+/)).uniq
end
def language

View File

@ -93,7 +93,7 @@ module ELFShim
return @dynamic_elf if defined? @dynamic_elf
@dynamic_elf = if HOMEBREW_PATCHELF_RB
patchelf_patcher.instance_variable_get(:@elf).segment_by_type(:DYNAMIC).present?
patchelf_patcher.elf.segment_by_type(:DYNAMIC).present?
elsif which "readelf"
Utils.popen_read("readelf", "-l", to_path).include?(" DYNAMIC ")
elsif which "file"

View File

@ -59,13 +59,30 @@ module OS
end
def languages
@languages ||= [
return @languages if @languages
os_langs = Utils.popen_read("defaults", "read", "-g", "AppleLanguages")
if os_langs.blank?
# User settings don't exist so check the system-wide one.
os_langs = Utils.popen_read("defaults", "read", "/Library/Preferences/.GlobalPreferences", "AppleLanguages")
end
os_langs = os_langs.scan(/[^ \n"(),]+/)
@languages = [
*Homebrew.args.value("language")&.split(","),
*ENV["HOMEBREW_LANGUAGES"]&.split(","),
*Open3.capture2("defaults", "read", "-g", "AppleLanguages")
.first
.scan(/[^ \n"(),]+/),
*os_langs,
].uniq
# Ensure all languages are valid
@languages.select! do |lang|
Locale.parse(lang)
true
rescue Locale::ParserError
false
end
@languages
end
def language

View File

@ -43,6 +43,10 @@ module OS
# For OS::Mac::Version compatibility
def requires_nehalem_cpu?
unless Hardware::CPU.intel?
raise "Unexpected architecture: #{Hardware::CPU.arch}. This only works with Intel architecture."
end
Hardware.oldest_cpu(self) == :nehalem
end
# https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)

View File

@ -86,7 +86,7 @@ class JavaRequirement < Requirement
end
def exact_version?
@version && @version.to_s.chars.last != "+"
@version && @version.to_s[-1] != "+"
end
def fits_latest?

View File

@ -29,7 +29,7 @@ class MacOSRequirement < Requirement
end
satisfy(build_env: false) do
next [*@version].any? { |v| MacOS.version.public_send(@comparator, v) } if version_specified?
next Array(@version).any? { |v| MacOS.version.public_send(@comparator, v) } if version_specified?
next true if OS.mac?
next true if @version

View File

@ -104,6 +104,27 @@ module RuboCop
@offensive_node = resource_block
@offense_source_range = resource_block.source_range
next if on_macos_blocks.length.zero? && on_linux_blocks.length.zero?
if on_macos_blocks.length == 1
on_macos_block = on_macos_blocks.first
child_nodes = on_macos_block.body.child_nodes
if child_nodes[0].method_name.to_s != "url" && child_nodes[1].method_name.to_s != "sha256"
problem "only an url and a sha256 (in the right order) are allowed in a `on_macos` " \
"block within a resource block."
next
end
end
if on_linux_blocks.length == 1
on_linux_block = on_linux_blocks.first
child_nodes = on_linux_block.body.child_nodes
if child_nodes[0].method_name.to_s != "url" && child_nodes[1].method_name.to_s != "sha256"
problem "only an url and a sha256 (in the right order) are allowed in a `on_linux` " \
"block within a resource block."
end
end
if on_macos_blocks.length > 1
problem "there can only be one `on_macos` block in a resource block."
next
@ -113,32 +134,6 @@ module RuboCop
problem "there can only be one `on_linux` block in a resource block."
next
end
if on_macos_blocks.length == 1 && on_linux_blocks.length.zero?
problem "you need to define an `on_linux` block within your resource block."
next
end
if on_macos_blocks.length.zero? && on_linux_blocks.length == 1
problem "you need to define an `on_macos` block within your resource block."
next
end
on_macos_block = on_macos_blocks.first
on_linux_block = on_linux_blocks.first
child_nodes = on_macos_block.body.child_nodes
if child_nodes[0].method_name.to_s != "url" && child_nodes[1].method_name.to_s != "sha256"
problem "only an url and a sha256 (in the right order) are allowed in a `on_macos` " \
"block within a resource block."
next
end
child_nodes = on_linux_block.body.child_nodes
if child_nodes[0].method_name.to_s != "url" && child_nodes[1].method_name.to_s != "sha256"
problem "only an url and a sha256 (in the right order) are allowed in a `on_linux` " \
"block within a resource block."
end
end
end

View File

@ -15,11 +15,40 @@ module RuboCop
bash-completion@2
].freeze
def audit_formula(_node, _class_node, _parent_class_node, body)
def audit_formula(_node, _class_node, _parent_class_node, body_node)
find_method_calls_by_name(body_node, :conflicts_with).each do |conflicts_with_call|
next unless parameters(conflicts_with_call).last.respond_to? :values
reason = parameters(conflicts_with_call).last.values.first
offending_node(reason)
name = Regexp.new(@formula_name, Regexp::IGNORECASE)
reason = string_content(reason).sub(name, "")
first_word = reason.split.first
if reason.match?(/\A[A-Z]/)
problem "'#{first_word}' from the `conflicts_with` reason should be '#{first_word.downcase}'."
end
problem "`conflicts_with` reason should not end with a period." if reason.end_with?(".")
end
return unless versioned_formula?
problem MSG if !ALLOWLIST.include?(@formula_name) &&
method_called_ever?(body, :conflicts_with)
method_called_ever?(body_node, :conflicts_with)
end
def autocorrect(node)
lambda do |corrector|
if versioned_formula?
corrector.replace(node.source_range, "keg_only :versioned_formula")
else
reason = string_content(node)
reason[0] = reason[0].downcase
reason = reason.delete_suffix(".")
corrector.replace(node.source_range, "\"#{reason}\"")
end
end
end
end
end

View File

@ -35,7 +35,7 @@ module RuboCop
# Checks for regex match of pattern in the node and
# sets the appropriate instance variables to report the match
def regex_match_group(node, pattern)
string_repr = string_content(node)
string_repr = string_content(node).encode("UTF-8", invalid: :replace)
match_object = string_repr.match(pattern)
return unless match_object

View File

@ -47,7 +47,7 @@ module RuboCop
# Check if command-line is wrongly used in formula's desc
if match = regex_match_group(desc, /(command ?line)/i)
c = match.to_s.chars.first
c = match.to_s[0]
problem "Description should use \"#{c}ommand-line\" instead of \"#{match}\""
end
@ -86,7 +86,7 @@ module RuboCop
correction = node.source
first_word = string_content(node).split.first
unless VALID_LOWERCASE_WORDS.include?(first_word)
first_char = first_word.to_s.chars.first
first_char = first_word.to_s[0]
correction.sub!(/^(['"]?)([a-z])/, "\\1#{first_char.upcase}") if first_char
end
correction.sub!(/^(['"]?)an?\s/i, "\\1")

View File

@ -37,7 +37,7 @@ module RuboCop
# https://wiki.freedesktop.org/project_name.
# "Software" is redirected to https://wiki.freedesktop.org/www/Software/project_name
when %r{^http://((?:www|nice|libopenraw|liboil|telepathy|xorg)\.)?freedesktop\.org/(?:wiki/)?}
if homepage =~ /Software/
if homepage.include?("Software")
problem "#{homepage} should be styled `https://wiki.freedesktop.org/www/Software/project_name`"
else
problem "#{homepage} should be styled `https://wiki.freedesktop.org/project_name`"

View File

@ -102,6 +102,23 @@ module RuboCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
problem "Use new-style option definitions" if find_method_def(body_node, :options)
if formula_tap == "homebrew-core"
# Use of build.with? implies options, which are forbidden in homebrew/core
find_instance_method_call(body_node, :build, :without?) do
problem "Formulae in homebrew/core should not use `build.without?`."
end
find_instance_method_call(body_node, :build, :with?) do
problem "Formulae in homebrew/core should not use `build.with?`."
end
return
end
depends_on_build_with(body_node) do |build_with_node|
offending_node(build_with_node)
problem "Use `:optional` or `:recommended` instead of `if #{build_with_node.source}`"
end
find_instance_method_call(body_node, :build, :without?) do |method|
next unless unless_modifier?(method.parent)
@ -143,29 +160,8 @@ module RuboCop
problem "Don't duplicate 'with': Use `build.with? \"#{match[1]}\"` to check for \"--with-#{match[1]}\""
end
find_instance_method_call(body_node, :build, :include?) do |method|
arg = parameters(method).first
next unless match = regex_match_group(arg, /^with(out)?-(.*)/)
problem "Use build.with#{match[1]}? \"#{match[2]}\" instead of " \
"build.include? 'with#{match[1]}-#{match[2]}'"
end
find_instance_method_call(body_node, :build, :include?) do |method|
arg = parameters(method).first
next unless match = regex_match_group(arg, /^--(.*)$/)
problem "Reference '#{match[1]}' without dashes"
end
return if formula_tap != "homebrew-core"
# Use of build.with? implies options, which are forbidden in homebrew/core
find_instance_method_call(body_node, :build, :without?) do
problem "Formulae in homebrew/core should not use `build.without?`."
end
find_instance_method_call(body_node, :build, :with?) do
problem "Formulae in homebrew/core should not use `build.with?`."
find_instance_method_call(body_node, :build, :include?) do
problem "`build.include?` is deprecated"
end
end
@ -174,6 +170,12 @@ module RuboCop
node.modifier_form? && node.unless?
end
# Finds `depends_on "foo" if build.with?("bar")` or `depends_on "foo" if build.without?("bar")`
def_node_search :depends_on_build_with, <<~EOS
(if $(send (send nil? :build) {:with? :without?} str)
(send nil? :depends_on str) nil?)
EOS
end
class MpiCheck < FormulaCop

View File

@ -6,7 +6,19 @@ module RuboCop
module Cop
module FormulaAudit
class Text < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
def audit_formula(node, _class_node, _parent_class_node, body_node)
@full_source_content = source_buffer(node).source
if match = @full_source_content.match(/^require ['"]formula['"]$/)
@offensive_node = node
@source_buf = source_buffer(node)
@line_no = match.pre_match.count("\n") + 1
@column = 0
@length = match[0].length
@offense_source_range = source_range(@source_buf, @line_no, @column, @length)
problem "`#{match}` is now unnecessary"
end
if !find_node_method_by_name(body_node, :plist_options) &&
find_method_def(body_node, :plist)
problem "Please set plist_options when using a formula-defined plist."
@ -62,7 +74,50 @@ module RuboCop
find_method_with_args(body_node, :system, "cargo", "build") do
problem "use \"cargo\", \"install\", *std_cargo_args"
end
find_every_method_call_by_name(body_node, :system).each do |m|
next unless parameters_passed?(m, /make && make/)
offending_node(m)
problem "Use separate `make` calls"
end
body_node.each_descendant(:dstr) do |dstr_node|
dstr_node.each_descendant(:begin) do |interpolation_node|
next unless interpolation_node.source.match?(/#\{\w+\s*\+\s*['"][^}]+\}/)
offending_node(interpolation_node)
problem "Do not concatenate paths in string interpolation"
end
end
find_strings(body_node).each do |n|
next unless regex_match_group(n, /JAVA_HOME/i)
next if @formula_name.match?(/^openjdk(@|$)/)
next if find_every_method_call_by_name(body_node, :depends_on).any? do |dependency|
dependency.each_descendant(:str).count.zero? ||
regex_match_group(dependency.each_descendant(:str).first, /^openjdk(@|$)/) ||
depends_on?(:java)
end
offending_node(n)
problem "Use `depends_on :java` to set JAVA_HOME"
end
prefix_path(body_node) do |prefix_node, path|
next unless match = path.match(%r{^(bin|include|libexec|lib|sbin|share|Frameworks)(?:/| |$)})
offending_node(prefix_node)
problem "Use `#{match[1].downcase}` instead of `prefix + \"#{match[1]}\"`"
end
end
# Find: prefix + "foo"
def_node_search :prefix_path, <<~EOS
$(send (send nil? :prefix) :+ (str $_))
EOS
end
end
@ -72,7 +127,42 @@ module RuboCop
find_method_with_args(body_node, :go_resource) do
problem "`go_resource`s are deprecated. Please ask upstream to implement Go vendoring"
end
find_method_with_args(body_node, :env, :userpaths) do
problem "`env :userpaths` in homebrew/core formulae is deprecated"
end
share_path_starts_with(body_node, @formula_name) do |share_node|
offending_node(share_node)
problem "Use `pkgshare` instead of `share/\"#{@formula_name}\"`"
end
interpolated_share_path_starts_with(body_node, "/#{@formula_name}") do |share_node|
offending_node(share_node)
problem "Use `\#{pkgshare}` instead of `\#{share}/#{@formula_name}`"
end
return unless formula_tap == "homebrew-core"
find_method_with_args(body_node, :env, :std) do
problem "`env :std` in homebrew/core formulae is deprecated"
end
end
# Check whether value starts with the formula name and then a "/", " " or EOS
def path_starts_with?(path, starts_with)
path.match?(%r{^#{Regexp.escape(starts_with)}(/| |$)})
end
# Find "#{share}/foo"
def_node_search :interpolated_share_path_starts_with, <<~EOS
$(dstr (begin (send nil? :share)) (str #path_starts_with?(%1)))
EOS
# Find share/"foo"
def_node_search :share_path_starts_with, <<~EOS
$(send (send nil? :share) :/ (str #path_starts_with?(%1)))
EOS
end
end
end

View File

@ -247,7 +247,7 @@ module RuboCop
# Don't use GitHub .zip files
zip_gh_pattern = %r{https://.*github.*/(archive|releases)/.*\.zip$}
audit_urls(urls, zip_gh_pattern) do |_, url|
next if url.match?(%r{releases/download})
next if url.include?("releases/download")
problem "Use GitHub tarballs rather than zipballs (url is #{url})."
end
@ -291,21 +291,22 @@ module RuboCop
urls += mirrors
# Check pypi urls
@pypi_pattern = %r{^https?://pypi.python.org/(.*)}
audit_urls(urls, @pypi_pattern) do |match, url|
problem "#{url} should be `https://files.pythonhosted.org/#{match[1]}`"
pypi_pattern = %r{^https?://pypi.python.org/}
audit_urls(urls, pypi_pattern) do |_, url|
problem "use the `Source` url found on PyPI downloads page (`#{get_pypi_url(url)}`)"
end
# Require long files.pythonhosted.org urls
pythonhosted_pattern = %r{^https?://files.pythonhosted.org/packages/source/}
audit_urls(urls, pythonhosted_pattern) do |_, url|
problem "use the `Source` url found on PyPI downloads page (`#{get_pypi_url(url)}`)"
end
end
def autocorrect(node)
lambda do |corrector|
url_string_node = parameters(node).first
url = string_content(url_string_node)
match = regex_match_group(url_string_node, @pypi_pattern)
correction = node.source.sub(url, "https://files.pythonhosted.org/#{match[1]}")
corrector.insert_before(node.source_range, correction)
corrector.remove(node.source_range)
end
def get_pypi_url(url)
package_file = File.basename(url)
package_name = package_file.match(/^(.+)-[a-z0-9.]+$/)[1]
"https://pypi.org/project/#{package_name}/#files"
end
end
end

View File

@ -15,7 +15,6 @@ module RuboCop
bc
bison
bzip2
cpio
cups
curl
dyld-headers
@ -62,6 +61,7 @@ module RuboCop
# TODO: consider making some of these keg-only.
ALLOWED_USES_FROM_MACOS_DEPS = (PROVIDED_BY_MACOS_FORMULAE + %w[
bash
cpio
expect
groff
gzip

View File

@ -47,12 +47,12 @@ class Sandbox
end
def allow_cvs
allow_write_path "#{ENV["HOME"]}/.cvspass"
allow_write_path "#{Dir.home(ENV["USER"])}/.cvspass"
end
def allow_fossil
allow_write_path "#{ENV["HOME"]}/.fossil"
allow_write_path "#{ENV["HOME"]}/.fossil-journal"
allow_write_path "#{Dir.home(ENV["USER"])}/.fossil"
allow_write_path "#{Dir.home(ENV["USER"])}/.fossil-journal"
end
def allow_write_cellar(formula)
@ -63,7 +63,7 @@ class Sandbox
# Xcode projects expect access to certain cache/archive dirs.
def allow_write_xcode
allow_write_path "#{ENV["HOME"]}/Library/Developer"
allow_write_path "#{Dir.home(ENV["USER"])}/Library/Developer"
end
def allow_write_log(formula)

View File

@ -19,7 +19,7 @@ module Searchable
def search_regex(regex)
select do |*args|
args = yield(*args) if block_given?
args = [*args].compact
args = Array(args).compact
args.any? { |arg| arg.match?(regex) }
end
end
@ -28,7 +28,7 @@ module Searchable
simplified_string = simplify_string(string)
select do |*args|
args = yield(*args) if block_given?
args = [*args].compact
args = Array(args).compact
args.any? { |arg| simplify_string(arg).include?(simplified_string) }
end
end

View File

@ -81,7 +81,6 @@ false:
- ./cask/utils.rb
- ./cask/verify.rb
- ./caveats.rb
- ./cleaner.rb
- ./cleanup.rb
- ./cli/args.rb
- ./cli/parser.rb
@ -129,15 +128,11 @@ false:
- ./cmd/uses.rb
- ./commands.rb
- ./compat/language/python.rb
- ./compilers.rb
- ./cxxstdlib.rb
- ./debrew.rb
- ./debrew/irb.rb
- ./dependencies.rb
- ./dependency.rb
- ./dependency_collector.rb
- ./description_cache_store.rb
- ./descriptions.rb
- ./dev-cmd/audit.rb
- ./dev-cmd/bottle.rb
- ./dev-cmd/bump-formula-pr.rb
@ -163,6 +158,7 @@ false:
- ./dev-cmd/release-notes.rb
- ./dev-cmd/ruby.rb
- ./dev-cmd/sh.rb
- ./dev-cmd/sponsors.rb
- ./dev-cmd/style.rb
- ./dev-cmd/tap-new.rb
- ./dev-cmd/test.rb
@ -174,7 +170,6 @@ false:
- ./development_tools.rb
- ./diagnostic.rb
- ./download_strategy.rb
- ./env_config.rb
- ./exceptions.rb
- ./extend/ENV.rb
- ./extend/ENV/shared.rb
@ -228,7 +223,6 @@ false:
- ./lock_file.rb
- ./migrator.rb
- ./missing_formula.rb
- ./os/linux.rb
- ./os/mac.rb
- ./os/mac/keg.rb
- ./os/mac/mach.rb
@ -454,9 +448,7 @@ false:
- ./utils/formatter.rb
- ./utils/git.rb
- ./utils/github.rb
- ./utils/notability.rb
- ./utils/popen.rb
- ./utils/user.rb
false:
- ./PATH.rb
@ -500,11 +492,8 @@ false:
- ./messages.rb
- ./mktemp.rb
- ./options.rb
- ./os.rb
- ./os/linux/elf.rb
- ./os/linux/glibc.rb
- ./os/linux/global.rb
- ./os/linux/kernel.rb
- ./os/mac/architecture_list.rb
- ./pkg_version.rb
- ./requirements/arch_requirement.rb
@ -603,6 +592,7 @@ false:
- ./test/dev-cmd/release-notes_spec.rb
- ./test/dev-cmd/ruby_spec.rb
- ./test/dev-cmd/sh_spec.rb
- ./test/dev-cmd/sponsors_spec.rb
- ./test/dev-cmd/style_spec.rb
- ./test/dev-cmd/tap-new_spec.rb
- ./test/dev-cmd/test_spec.rb
@ -848,8 +838,6 @@ false:
- ./unpack_strategy/uncompressed.rb
- ./utils/gems.rb
- ./utils/inreplace.rb
- ./utils/link.rb
- ./utils/shebang.rb
- ./version.rb
true:
@ -860,7 +848,13 @@ true:
- ./cask/macos.rb
- ./cask/url.rb
- ./checksum.rb
- ./cleaner.rb
- ./compilers.rb
- ./config.rb
- ./dependency_collector.rb
- ./description_cache_store.rb
- ./descriptions.rb
- ./env_config.rb
- ./extend/cachable.rb
- ./extend/os/linux/development_tools.rb
- ./extend/os/linux/formula.rb
@ -881,6 +875,10 @@ true:
- ./locale.rb
- ./metafiles.rb
- ./official_taps.rb
- ./os.rb
- ./os/linux.rb
- ./os/linux/glibc.rb
- ./os/linux/kernel.rb
- ./rubocops/cask/ast/cask_header.rb
- ./rubocops/cask/ast/stanza.rb
- ./rubocops/cask/constants/stanza.rb
@ -890,9 +888,13 @@ true:
- ./test/support/helper/fixtures.rb
- ./test/support/lib/config.rb
- ./utils/bottles.rb
- ./utils/link.rb
- ./utils/notability.rb
- ./utils/shebang.rb
- ./utils/shell.rb
- ./utils/svn.rb
- ./utils/tty.rb
- ./utils/user.rb
- ./version/null.rb
strict:

View File

@ -1,5 +1,5 @@
# This file is autogenerated. Do not edit it by hand. Regenerate it with:
# tapioca sync
# tapioca sync --exclude json
# typed: true

View File

@ -1,5 +1,5 @@
# This file is autogenerated. Do not edit it by hand. Regenerate it with:
# tapioca sync
# tapioca sync --exclude json
# typed: true
@ -12,6 +12,24 @@ end
module RuboCop::Cop::Performance
end
class RuboCop::Cop::Performance::AncestorsInclude < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
def ancestors_include_candidate?(node = _); end
def autocorrect(node); end
def on_send(node); end
end
RuboCop::Cop::Performance::AncestorsInclude::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::BigDecimalWithNumericArgument < ::RuboCop::Cop::Cop
def autocorrect(node); end
def big_decimal_with_numeric_argument?(node = _); end
def on_send(node); end
end
RuboCop::Cop::Performance::BigDecimalWithNumericArgument::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::BindCall < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
extend(::RuboCop::Cop::TargetRubyVersion)
@ -256,6 +274,29 @@ class RuboCop::Cop::Performance::InefficientHashSearch < ::RuboCop::Cop::Cop
def use_long_method; end
end
class RuboCop::Cop::Performance::IoReadlines < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
def autocorrect(node); end
def on_send(node); end
def readlines_on_class?(node = _); end
def readlines_on_instance?(node = _); end
private
def build_bad_method(enumerable_call); end
def build_call_args(call_args_node); end
def build_good_method(enumerable_call); end
def correction_range(enumerable_call, readlines_call); end
def enumerable_method?(node); end
def offense(node, enumerable_call, readlines_call); end
def offense_range(enumerable_call, readlines_call); end
end
RuboCop::Cop::Performance::IoReadlines::ENUMERABLE_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::Cop::Performance::IoReadlines::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::OpenStruct < ::RuboCop::Cop::Cop
def on_send(node); end
def open_struct(node = _); end
@ -349,6 +390,42 @@ RuboCop::Cop::Performance::RedundantMerge::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Performance::RedundantMerge::WITH_MODIFIER_CORRECTION = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::RedundantSortBlock < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
include(::RuboCop::Cop::SortBlock)
def autocorrect(node); end
def on_block(node); end
private
def message(var_a, var_b); end
end
RuboCop::Cop::Performance::RedundantSortBlock::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::RedundantStringChars < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
def autocorrect(node); end
def on_send(node); end
def redundant_chars_call?(node = _); end
private
def build_bad_method(method, args); end
def build_call_args(call_args_node); end
def build_good_method(method, args); end
def build_message(method, args); end
def correction_range(receiver, node); end
def offense_range(receiver, node); end
def replaceable_method?(method_name); end
end
RuboCop::Cop::Performance::RedundantStringChars::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Performance::RedundantStringChars::REPLACEABLE_METHODS = T.let(T.unsafe(nil), Array)
class RuboCop::Cop::Performance::RegexpMatch < ::RuboCop::Cop::Cop
def autocorrect(node); end
def last_matches(node0); end
@ -398,21 +475,61 @@ RuboCop::Cop::Performance::ReverseEach::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Performance::ReverseEach::UNDERSCORE = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::Size < ::RuboCop::Cop::Cop
class RuboCop::Cop::Performance::ReverseFirst < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
def autocorrect(node); end
def on_send(node); end
def reverse_first_candidate?(node = _); end
private
def allowed_parent?(node); end
def array?(node); end
def eligible_node?(node); end
def eligible_receiver?(node); end
def hash?(node); end
def build_bad_method(node); end
def build_good_method(node); end
def build_message(node); end
def correction_range(receiver, node); end
end
RuboCop::Cop::Performance::ReverseFirst::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::Size < ::RuboCop::Cop::Cop
def array?(node = _); end
def autocorrect(node); end
def count?(node = _); end
def hash?(node = _); end
def on_send(node); end
end
RuboCop::Cop::Performance::Size::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::SortReverse < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
include(::RuboCop::Cop::SortBlock)
def autocorrect(node); end
def on_block(node); end
private
def message(var_a, var_b); end
end
RuboCop::Cop::Performance::SortReverse::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::Squeeze < ::RuboCop::Cop::Cop
def autocorrect(node); end
def on_send(node); end
def squeeze_candidate?(node = _); end
private
def repeating_literal?(regex_str); end
end
RuboCop::Cop::Performance::Squeeze::MSG = T.let(T.unsafe(nil), String)
RuboCop::Cop::Performance::Squeeze::PREFERRED_METHODS = T.let(T.unsafe(nil), Hash)
class RuboCop::Cop::Performance::StartWith < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RegexpMetacharacter)
@ -424,6 +541,19 @@ end
RuboCop::Cop::Performance::StartWith::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::StringInclude < ::RuboCop::Cop::Cop
def autocorrect(node); end
def on_match_with_lvasgn(node); end
def on_send(node); end
def redundant_regex?(node = _); end
private
def literal?(regex_str); end
end
RuboCop::Cop::Performance::StringInclude::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::Performance::StringReplacement < ::RuboCop::Cop::Cop
include(::RuboCop::Cop::RangeHelp)
@ -504,6 +634,18 @@ module RuboCop::Cop::RegexpMetacharacter
def safe_multiline?; end
end
module RuboCop::Cop::SortBlock
include(::RuboCop::Cop::RangeHelp)
extend(::RuboCop::AST::NodePattern::Macros)
def replaceable_body?(node = _, param1, param2); end
def sort_with_block?(node = _); end
private
def sort_range(send, node); end
end
RuboCop::NodePattern = RuboCop::AST::NodePattern
module RuboCop::Performance

View File

@ -1,5 +1,5 @@
# This file is autogenerated. Do not edit it by hand. Regenerate it with:
# tapioca sync
# tapioca sync --exclude json
# typed: true
@ -225,7 +225,6 @@ class RuboCop::Cop::RSpec::DescribeClass < ::RuboCop::Cop::RSpec::Cop
def describe_with_rails_metadata?(node = _); end
def on_top_level_describe(node, _); end
def rails_metadata?(node = _); end
def shared_group?(node = _); end
def valid_describe?(node = _); end
private
@ -528,7 +527,7 @@ end
class RuboCop::Cop::RSpec::FactoryBot::AttributeDefinedStatically < ::RuboCop::Cop::RSpec::Cop
def association?(node = _); end
def autocorrect(node); end
def factory_attributes(node0); end
def factory_attributes(node = _); end
def on_block(node); end
def value_matcher(node = _); end
@ -773,12 +772,13 @@ end
RuboCop::Cop::RSpec::InstanceSpy::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::RSpec::InstanceVariable < ::RuboCop::Cop::RSpec::Cop
include(::RuboCop::RSpec::TopLevelGroup)
def custom_matcher?(node = _); end
def dynamic_class?(node = _); end
def ivar_assigned?(node0, param1); end
def ivar_usage(node0); end
def on_block(node); end
def spec_group?(node = _); end
def on_top_level_group(node); end
private
@ -786,8 +786,6 @@ class RuboCop::Cop::RSpec::InstanceVariable < ::RuboCop::Cop::RSpec::Cop
def valid_usage?(node); end
end
RuboCop::Cop::RSpec::InstanceVariable::EXAMPLE_GROUP_METHODS = T.let(T.unsafe(nil), RuboCop::RSpec::Language::SelectorSet)
RuboCop::Cop::RSpec::InstanceVariable::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::RSpec::InvalidPredicateMatcher < ::RuboCop::Cop::RSpec::Cop
@ -844,7 +842,6 @@ end
RuboCop::Cop::RSpec::LeadingSubject::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::RSpec::LeakyConstantDeclaration < ::RuboCop::Cop::RSpec::Cop
def in_example_or_shared_group?(node = _); end
def on_casgn(node); end
def on_class(node); end
def on_module(node); end
@ -875,12 +872,14 @@ end
RuboCop::Cop::RSpec::LetBeforeExamples::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::RSpec::LetSetup < ::RuboCop::Cop::RSpec::Cop
def let_bang(node0); end
def example_or_shared_group_or_including?(node = _); end
def let_bang(node = _); end
def method_called?(node0, param1); end
def on_block(node); end
private
def child_let_bang(node, &block); end
def unused_let_bang(node); end
end
@ -993,12 +992,11 @@ class RuboCop::Cop::RSpec::NestedGroups < ::RuboCop::Cop::RSpec::Cop
include(::RuboCop::Cop::ConfigurableMax)
include(::RuboCop::RSpec::TopLevelDescribe)
def find_contexts(node0); end
def on_top_level_describe(node, _args); end
private
def find_nested_contexts(node, nesting: _, &block); end
def find_nested_example_groups(node, nesting: _, &block); end
def max_nesting; end
def max_nesting_config; end
def message(nesting); end
@ -1157,6 +1155,7 @@ class RuboCop::Cop::RSpec::ReturnFromStub < ::RuboCop::Cop::RSpec::Cop
def contains_stub?(node0); end
def on_block(node); end
def on_send(node); end
def stub_with_block?(node = _); end
private
@ -1280,16 +1279,17 @@ end
RuboCop::Cop::RSpec::SingleArgumentMessageChain::MSG = T.let(T.unsafe(nil), String)
class RuboCop::Cop::RSpec::SubjectStub < ::RuboCop::Cop::RSpec::Cop
include(::RuboCop::RSpec::TopLevelGroup)
def message_expectation?(node = _, param1); end
def message_expectation_matcher?(node0); end
def on_block(node); end
def on_top_level_group(node); end
def subject(node = _); end
private
def find_all_explicit_subjects(node); end
def find_subject_expectations(node, subject_names = _, &block); end
def processed_example_groups; end
end
RuboCop::Cop::RSpec::SubjectStub::MSG = T.let(T.unsafe(nil), String)
@ -1467,17 +1467,14 @@ end
class RuboCop::RSpec::ExampleGroup < ::RuboCop::RSpec::Concept
def examples; end
def hooks; end
def lets; end
def scope_change?(node = _); end
def subjects; end
private
def examples_in_scope(node, &blk); end
def find_examples(node); end
def find_hooks(node); end
def find_subjects(node); end
def hooks_in_scope(node); end
def subjects_in_scope(node); end
def find_all(node, predicate); end
def find_all_in_scope(node, predicate); end
end
module RuboCop::RSpec::FactoryBot
@ -1576,6 +1573,8 @@ module RuboCop::RSpec::Language::NodePattern
def example_group_with_body?(node = _); end
def hook?(node = _); end
def let?(node = _); end
def shared_group?(node = _); end
def spec_group?(node = _); end
def subject?(node = _); end
end
@ -1636,6 +1635,21 @@ module RuboCop::RSpec::TopLevelDescribe
def top_level_nodes; end
end
module RuboCop::RSpec::TopLevelGroup
include(::RuboCop::RSpec::Language)
extend(::RuboCop::AST::NodePattern::Macros)
def example_or_shared_group?(node = _); end
def on_block(node); end
private
def root_node; end
def top_level_group?(node); end
def top_level_groups; end
def top_level_nodes; end
end
module RuboCop::RSpec::Variable
include(::RuboCop::RSpec::Language)
extend(::RuboCop::AST::NodePattern::Macros)

View File

@ -5819,6 +5819,10 @@ class Cask::DSL::Container
def nested=(nested); end
def pairs(); end
def pairs=(pairs); end
def type(); end
def type=(type); end
@ -19436,7 +19440,7 @@ module RuboCop::RSpec::ExpectOffense
def expect_no_offenses(source, file=T.unsafe(nil)); end
def expect_offense(source, file=T.unsafe(nil), **replacements); end
def expect_offense(source, file=T.unsafe(nil), severity: T.unsafe(nil), **replacements); end
def format_offense(source, **replacements); end
end
@ -23216,6 +23220,8 @@ class URL
def scheme=(scheme); end
def specs(); end
def string(); end
def subdomain(); end
@ -23234,6 +23240,8 @@ class URL
def trust_cert(); end
def uri(); end
def user_agent(); end
def using(); end

View File

@ -0,0 +1,14 @@
# typed: true
module OS
module Linux
include Kernel
def which(cmd, path = ENV["PATH"])
end
end
module Mac
include Kernel
end
end

View File

@ -0,0 +1,15 @@
# typed: strict
module SharedAudits
def github(user, repo)
end
def gitlab(user, repo)
end
def bitbucket(user, repo)
end
def curl_output(*args, secrets: [], **options)
end
end

View File

@ -0,0 +1,9 @@
# typed: strict
class User < String
def gui?
end
def self.current
end
end

View File

@ -5,4 +5,12 @@ module Utils
class Bottles
end
module Link
include Kernel
end
module Shebang
include Kernel
end
end

View File

@ -61,7 +61,7 @@ class SystemCommand
@executable = executable
@args = args
@sudo = sudo
@input = [*input]
@input = Array(input)
@print_stdout = print_stdout
@print_stderr = print_stderr
@verbose = verbose

View File

@ -21,7 +21,7 @@ RSpec/InstanceVariable:
- 'utils/git_spec.rb'
- 'version_spec.rb'
# Offense count: 74
# Offense count: 75
RSpec/MultipleDescribes:
Exclude:
- 'ENV_spec.rb'
@ -94,6 +94,7 @@ RSpec/MultipleDescribes:
- 'rubocops/class_spec.rb'
- 'rubocops/formula_desc_spec.rb'
- 'rubocops/lines_spec.rb'
- 'rubocops/text_spec.rb'
- 'rubocops/urls_spec.rb'
- 'software_spec_spec.rb'
- 'tap_spec.rb'

View File

@ -20,6 +20,26 @@ describe Cask::Cmd::List, :cask do
EOS
end
it "lists oneline" do
casks = %w[
local-caffeine
third-party/tap/third-party-cask
local-transmission
].map { |c| Cask::CaskLoader.load(c) }
casks.each do |c|
InstallHelper.install_with_caskfile(c)
end
expect {
described_class.run("-1")
}.to output(<<~EOS).to_stdout
local-caffeine
local-transmission
third-party-cask
EOS
end
it "lists full names" do
casks = %w[
local-caffeine
@ -66,6 +86,31 @@ describe Cask::Cmd::List, :cask do
end
end
describe "lists json" do
let(:casks) { ["local-caffeine", "local-transmission"] }
let(:expected_output) {
<<~EOS
[{"token":"local-caffeine","name":[],"homepage":"https://brew.sh/","url":"file:///usr/local/Homebrew/Library/Homebrew/test/support/fixtures/cask/caffeine.zip","appcast":null,"version":"1.2.3","sha256":"67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94","artifacts":[["Caffeine.app"]],"caveats":null,"depends_on":{},"conflicts_with":null,"container":null,"auto_updates":null},{"token":"local-transmission","name":["Transmission"],"homepage":"https://brew.sh/","url":"file:///usr/local/Homebrew/Library/Homebrew/test/support/fixtures/cask/transmission-2.61.dmg","appcast":null,"version":"2.61","sha256":"e44ffa103fbf83f55c8d0b1bea309a43b2880798dae8620b1ee8da5e1095ec68","artifacts":[["Transmission.app"]],"caveats":null,"depends_on":{},"conflicts_with":null,"container":null,"auto_updates":null}]
EOS
}
before do
casks.map(&Cask::CaskLoader.method(:load)).each(&InstallHelper.method(:install_with_caskfile))
end
it "of all installed Casks" do
expect {
described_class.run("--json")
}.to output(expected_output).to_stdout
end
it "of given Casks" do
expect {
described_class.run("--json", "local-caffeine", "local-transmission")
}.to output(expected_output).to_stdout
end
end
describe "given a set of installed Casks" do
let(:caffeine) { Cask::CaskLoader.load(cask_path("local-caffeine")) }
let(:transmission) { Cask::CaskLoader.load(cask_path("local-transmission")) }

View File

@ -179,60 +179,6 @@ module Homebrew
end
end
# Intentionally outputted non-interpolated strings
# rubocop:disable Lint/InterpolationCheck
describe "#line_problems" do
specify "pkgshare" do
fa = formula_auditor "foo", <<~RUBY, strict: true
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
end
RUBY
fa.line_problems 'ohai "#{share}/foo"', 3
expect(fa.problems.shift).to eq("Use \#{pkgshare} instead of \#{share}/foo")
fa.line_problems 'ohai "#{share}/foo/bar"', 3
expect(fa.problems.shift).to eq("Use \#{pkgshare} instead of \#{share}/foo")
fa.line_problems 'ohai share/"foo"', 3
expect(fa.problems.shift).to eq('Use pkgshare instead of (share/"foo")')
fa.line_problems 'ohai share/"foo/bar"', 3
expect(fa.problems.shift).to eq('Use pkgshare instead of (share/"foo")')
fa.line_problems 'ohai "#{share}/foo-bar"', 3
expect(fa.problems).to eq([])
fa.line_problems 'ohai share/"foo-bar"', 3
expect(fa.problems).to eq([])
fa.line_problems 'ohai share/"bar"', 3
expect(fa.problems).to eq([])
end
# Regression test for https://github.com/Homebrew/legacy-homebrew/pull/48744
# Formulae with "++" in their name would break various audit regexps:
# Error: nested *?+ in regexp: /^libxml++3\s/
specify "++ in name" do
fa = formula_auditor "foolibc++", <<~RUBY, strict: true
class Foolibcxx < Formula
desc "foolibc++ is a test"
url "https://brew.sh/foo-1.0.tgz"
end
RUBY
fa.line_problems 'ohai "#{share}/foolibc++"', 3
expect(fa.problems.shift)
.to eq("Use \#{pkgshare} instead of \#{share}/foolibc++")
fa.line_problems 'ohai share/"foolibc++"', 3
expect(fa.problems.shift)
.to eq('Use pkgshare instead of (share/"foolibc++")')
end
end
# rubocop:enable Lint/InterpolationCheck
describe "#audit_github_repository" do
specify "#audit_github_repository when HOMEBREW_NO_GITHUB_API is set" do
ENV["HOMEBREW_NO_GITHUB_API"] = "1"
@ -596,7 +542,7 @@ module Homebrew
include_examples "formulae exist", described_class::VERSIONED_KEG_ONLY_ALLOWLIST
include_examples "formulae exist", described_class::VERSIONED_HEAD_SPEC_ALLOWLIST
include_examples "formulae exist", described_class::USES_FROM_MACOS_ALLOWLIST
include_examples "formulae exist", described_class::THROTTLED_DENYLIST.keys
include_examples "formulae exist", described_class::THROTTLED_FORMULAE.keys
include_examples "formulae exist", described_class::UNSTABLE_ALLOWLIST.keys
include_examples "formulae exist", described_class::GNOME_DEVEL_ALLOWLIST.keys
end

View File

@ -50,6 +50,7 @@ describe OS::Mac::Version do
end
specify "#requires_nehalem_cpu?" do
expect(Hardware::CPU).to receive(:type).at_least(:twice).and_return(:intel)
expect(described_class.new("10.14").requires_nehalem_cpu?).to be true
expect(described_class.new("10.12").requires_nehalem_cpu?).to be false
end

View File

@ -447,12 +447,10 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
end
it "there is a on_macos block but no on_linux block" do
expect_offense(<<~RUBY)
expect_no_offenses(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
resource do
^^^^^^^^^^^ you need to define an `on_linux` block within your resource block.
on_macos do
url "https://brew.sh/resource1.tar.gz"
sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"
@ -463,12 +461,10 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
end
it "there is a on_linux block but no on_macos block" do
expect_offense(<<~RUBY)
expect_no_offenses(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
resource do
^^^^^^^^^^^ you need to define an `on_macos` block within your resource block.
on_linux do
url "https://brew.sh/resource1.tar.gz"
sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"

View File

@ -5,14 +5,34 @@ require "rubocops/conflicts"
describe RuboCop::Cop::FormulaAudit::Conflicts do
subject(:cop) { described_class.new }
context "When auditing formula for conflicts with" do
it "multiple conflicts_with" do
context "When auditing conflicts_with" do
it "conflicts_with reason is capitalized" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
conflicts_with "bar", :because => "Reason"
^^^^^^^^ 'Reason' from the `conflicts_with` reason should be 'reason'.
conflicts_with "baz", :because => "Foo is the formula name which does not require downcasing"
end
RUBY
end
it "conflicts_with reason ends with a period" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
conflicts_with "bar", "baz", :because => "reason."
^^^^^^^^^ `conflicts_with` reason should not end with a period.
end
RUBY
end
it "conflicts_with in a versioned formula" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo@2.0.rb")
class FooAT20 < Formula
url 'https://brew.sh/foo-2.0.tgz'
conflicts_with "mysql", "mariadb", "percona-server",
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Versioned formulae should not use `conflicts_with`. Use `keg_only :versioned_formula` instead.
:because => "both install plugins"
conflicts_with "mysql", "mariadb"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Versioned formulae should not use `conflicts_with`. Use `keg_only :versioned_formula` instead.
end
RUBY
end
@ -21,10 +41,48 @@ describe RuboCop::Cop::FormulaAudit::Conflicts do
expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo@2.0.rb")
class FooAT20 < Formula
url 'https://brew.sh/foo-2.0.tgz'
desc 'Bar'
homepage "https://brew.sh"
end
RUBY
end
it "auto-corrects capitalized reason" do
source = <<~RUBY
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
conflicts_with "bar", :because => "Reason"
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
conflicts_with "bar", :because => "reason"
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
it "auto-corrects trailing period" do
source = <<~RUBY
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
conflicts_with "bar", :because => "reason."
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
conflicts_with "bar", :because => "reason"
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
end
include_examples "formulae exist", described_class::ALLOWLIST

View File

@ -73,8 +73,8 @@ describe RuboCop::Cop::FormulaAudit::Homepage do
RUBY
inspect_source(source)
if homepage.match?(%r{http://www\.freedesktop\.org})
if homepage.match?(/Software/)
if homepage.include?("http://www.freedesktop.org")
if homepage.include?("Software")
expected_offenses = [{ message: "#{homepage} should be styled " \
"`https://wiki.freedesktop.org/www/Software/project_name`",
severity: :convention,
@ -89,7 +89,7 @@ describe RuboCop::Cop::FormulaAudit::Homepage do
column: 2,
source: source }]
end
elsif homepage.match?(%r{https://code\.google\.com})
elsif homepage.include?("https://code.google.com")
expected_offenses = [{ message: "#{homepage} should end with a slash",
severity: :convention,
line: 2,

View File

@ -201,6 +201,24 @@ describe RuboCop::Cop::FormulaAudit::OptionDeclarations do
RUBY
end
it "build.without? in dependencies" do
expect_offense(<<~RUBY)
class Foo < Formula
depends_on "bar" if build.without?("baz")
^^^^^^^^^^^^^^^^^^^^^ Use `:optional` or `:recommended` instead of `if build.without?("baz")`
end
RUBY
end
it "build.with? in dependencies" do
expect_offense(<<~RUBY)
class Foo < Formula
depends_on "bar" if build.with?("baz")
^^^^^^^^^^^^^^^^^^ Use `:optional` or `:recommended` instead of `if build.with?("baz")`
end
RUBY
end
it "unless build.without? conditional" do
expect_offense(<<~RUBY)
class Foo < Formula
@ -279,27 +297,14 @@ describe RuboCop::Cop::FormulaAudit::OptionDeclarations do
RUBY
end
it "build.include? conditional" do
it "build.include? deprecated" do
expect_offense(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def post_install
return if build.include? "without-bar"
^^^^^^^^^^^ Use build.without? \"bar\" instead of build.include? 'without-bar'
end
end
RUBY
end
it "build.include? with dashed args conditional" do
expect_offense(<<~RUBY)
class Foo < Formula
desc "foo"
url 'https://brew.sh/foo-1.0.tgz'
def post_install
return if build.include? "--bar"
^^^^^ Reference 'bar' without dashes
return if build.include? "foo"
^^^^^^^^^^^^^^^^^^^^ `build.include?` is deprecated
end
end
RUBY

View File

@ -48,7 +48,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
EOS
inspect_source(source)
expected_offense = if patch_url.match?(%r{/raw\.github\.com/})
expected_offense = if patch_url.include?("/raw.github.com/")
[{ message:
<<~EOS.chomp,
GitHub/Gist patches should specify a revision:
@ -58,7 +58,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5,
column: 12,
source: source }]
elsif patch_url.match?(%r{macports/trunk})
elsif patch_url.include?("macports/trunk")
[{ message:
<<~EOS.chomp,
MacPorts patches should specify a revision instead of trunk:
@ -232,7 +232,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
RUBY
inspect_source(source)
expected_offense = if patch_url.match?(%r{/raw\.github\.com/})
expected_offense = if patch_url.include?("/raw.github.com/")
[{ message:
<<~EOS.chomp,
GitHub/Gist patches should specify a revision:
@ -242,7 +242,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
line: 5,
column: 16,
source: source }]
elsif patch_url.match?(%r{macports/trunk})
elsif patch_url.include?("macports/trunk")
[{ message:
<<~EOS.chomp,
MacPorts patches should specify a revision instead of trunk:

View File

@ -6,6 +6,17 @@ describe RuboCop::Cop::FormulaAudit::Text do
subject(:cop) { described_class.new }
context "When auditing formula text" do
it "with `require \"formula\"` is present" do
expect_offense(<<~RUBY)
require "formula"
^^^^^^^^^^^^^^^^^ `require "formula"` is now unnecessary
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
homepage "https://brew.sh"
end
RUBY
end
it "with both openssl and libressl optional dependencies" do
expect_offense(<<~RUBY)
class Foo < Formula
@ -215,5 +226,248 @@ describe RuboCop::Cop::FormulaAudit::Text do
end
RUBY
end
it "When make calls are not separated" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
system "make && make install"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use separate `make` calls
end
end
RUBY
end
it "When concatenating in string interpolation" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
ohai "foo \#{bar + "baz"}"
^^^^^^^^^^^^^^ Do not concatenate paths in string interpolation
end
end
RUBY
end
it "When using JAVA_HOME without a java dependency" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
ohai "JAVA_HOME"
^^^^^^^^^^^ Use `depends_on :java` to set JAVA_HOME
end
end
RUBY
end
it "When using JAVA_HOME with an openjdk dependency" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
depends_on "openjdk"
def install
ohai "JAVA_HOME"
end
end
RUBY
end
it "When using JAVA_HOME with an openjdk build dependency" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
depends_on "openjdk" => :build
def install
ohai "JAVA_HOME"
end
end
RUBY
end
it "When using JAVA_HOME with a java dependency" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
depends_on :java
def install
ohai "JAVA_HOME"
end
end
RUBY
end
it "When using JAVA_HOME with a java build dependency" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
depends_on :java => :build
def install
ohai "JAVA_HOME"
end
end
RUBY
end
it "When using `prefix + \"bin\"` instead of `bin`" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
ohai prefix + "bin"
^^^^^^^^^^^^^^ Use `bin` instead of `prefix + "bin"`
end
end
RUBY
end
it "When using `prefix + \"bin/foo\"` instead of `bin`" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
ohai prefix + "bin/foo"
^^^^^^^^^^^^^^^^^^ Use `bin` instead of `prefix + "bin"`
end
end
RUBY
end
end
end
describe RuboCop::Cop::FormulaAuditStrict::Text do
subject(:cop) { described_class.new }
context "When auditing formula text" do
it "when deprecated `env :userpaths` is present" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
env :userpaths
^^^^^^^^^^^^^^ `env :userpaths` in homebrew/core formulae is deprecated
end
RUBY
end
it "when deprecated `env :std` is present in homebrew-core" do
expect_offense(<<~RUBY, "/homebrew-core/")
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
env :std
^^^^^^^^ `env :std` in homebrew/core formulae is deprecated
end
RUBY
end
it "when `\#{share}/foo` is used instead of `\#{pkgshare}`" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai "\#{share}/foo"
^^^^^^^^^^^^^^ Use `\#{pkgshare}` instead of `\#{share}/foo`
end
end
RUBY
end
it "when `\#{share}/foo/bar` is used instead of `\#{pkgshare}/bar`" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai "\#{share}/foo/bar"
^^^^^^^^^^^^^^^^^^ Use `\#{pkgshare}` instead of `\#{share}/foo`
end
end
RUBY
end
it "when `\#{share}/foolibc++` is used instead of `\#{pkgshare}/foolibc++`" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foolibc++.rb")
class Foo < Formula
def install
ohai "\#{share}/foolibc++"
^^^^^^^^^^^^^^^^^^^^ Use `\#{pkgshare}` instead of `\#{share}/foolibc++`
end
end
RUBY
end
it "when `share/\"foo\"` is used instead of `pkgshare`" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai share/"foo"
^^^^^^^^^^^ Use `pkgshare` instead of `share/"foo"`
end
end
RUBY
end
it "when `share/\"foo/bar\"` is used instead of `pkgshare`" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai share/"foo/bar"
^^^^^^^^^^^^^^^ Use `pkgshare` instead of `share/"foo"`
end
end
RUBY
end
it "when `share/\"foolibc++\"` is used instead of `pkgshare`" do
expect_offense(<<~RUBY, "/homebrew-core/Formula/foolibc++.rb")
class Foo < Formula
def install
ohai share/"foolibc++"
^^^^^^^^^^^^^^^^^ Use `pkgshare` instead of `share/"foolibc++"`
end
end
RUBY
end
it "when `\#{share}/foo-bar` doesn't match formula name" do
expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai "\#{share}/foo-bar"
end
end
RUBY
end
it "when `share/foo-bar` doesn't match formula name" do
expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai share/"foo-bar"
end
end
RUBY
end
it "when `share/bar` doesn't match formula name" do
expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai share/"bar"
end
end
RUBY
end
it "when formula name appears afer `share/\"bar\"`" do
expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai share/"bar/foo"
end
end
RUBY
end
it "when formula name appears afer `\"\#{share}/bar\"`" do
expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo.rb")
class Foo < Formula
def install
ohai "\#{share}/bar/foo"
end
end
RUBY
end
end
end

View File

@ -245,29 +245,32 @@ end
describe RuboCop::Cop::FormulaAudit::PyPiUrls do
subject(:cop) { described_class.new }
context "when a pypi.python.org URL is used" do
it "reports an offense" do
context "when a pypi URL is used" do
it "reports an offense for pypi.python.org urls" do
expect_offense(<<~RUBY)
class Foo < Formula
desc "foo"
url "https://pypi.python.org/packages/source/foo/foo-0.1.tar.gz"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ https://pypi.python.org/packages/source/foo/foo-0.1.tar.gz should be `https://files.pythonhosted.org/packages/source/foo/foo-0.1.tar.gz`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use the `Source` url found on PyPI downloads page (`https://pypi.org/project/foo/#files`)
end
RUBY
end
it "support auto-correction" do
corrected = autocorrect_source(<<~RUBY)
it "reports an offense for short file.pythonhosted.org urls" do
expect_offense(<<~RUBY)
class Foo < Formula
desc "foo"
url "https://pypi.python.org/packages/source/foo/foo-0.1.tar.gz"
url "https://files.pythonhosted.org/packages/source/f/foo/foo-0.1.tar.gz"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use the `Source` url found on PyPI downloads page (`https://pypi.org/project/foo/#files`)
end
RUBY
end
expect(corrected).to eq <<~RUBY
it "reports no offenses for long file.pythonhosted.org urls" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
desc "foo"
url "https://files.pythonhosted.org/packages/source/foo/foo-0.1.tar.gz"
url "https://files.pythonhosted.org/packages/a0/b1/a01b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f/foo-0.1.tar.gz"
end
RUBY
end

View File

@ -161,6 +161,12 @@ RSpec.shared_context "integration test" do
content = <<~RUBY
url "https://brew.sh/#{name}-1.0"
RUBY
when "package_license"
content = <<~RUBY
url "https://brew.sh/#patchelf-1.0"
license "0BSD"
RUBY
end
Formulary.core_path(name).tap do |formula_path|

View File

@ -9,35 +9,67 @@ describe Git do
HOMEBREW_CACHE.cd do
system git, "init"
File.open(file, "w") { |f| f.write("blah") }
system git, "add", HOMEBREW_CACHE/file
File.open("README.md", "w") { |f| f.write("README") }
system git, "add", HOMEBREW_CACHE/"README.md"
system git, "commit", "-m", "'File added'"
@h1 = `git rev-parse HEAD`
File.open(file, "w") { |f| f.write("brew") }
system git, "add", HOMEBREW_CACHE/file
File.open("README.md", "w") { |f| f.write("# README") }
system git, "add", HOMEBREW_CACHE/"README.md"
system git, "commit", "-m", "'written to File'"
@h2 = `git rev-parse HEAD`
File.open("LICENSE.txt", "w") { |f| f.write("LICENCE") }
system git, "add", HOMEBREW_CACHE/"LICENSE.txt"
system git, "commit", "-m", "'File added'"
@h3 = `git rev-parse HEAD`
File.open("LICENSE.txt", "w") { |f| f.write("LICENSE") }
system git, "add", HOMEBREW_CACHE/"LICENSE.txt"
system git, "commit", "-m", "'written to File'"
end
end
let(:file) { "blah.rb" }
let(:hash1) { @h1[0..6] }
let(:hash2) { @h2[0..6] }
let(:file) { "README.md" }
let(:file_hash1) { @h1[0..6] }
let(:file_hash2) { @h2[0..6] }
let(:files) { ["README.md", "LICENSE.txt"] }
let(:files_hash1) { [@h3[0..6], ["LICENSE.txt"]] }
let(:files_hash2) { [@h2[0..6], ["README.md"]] }
describe "#last_revision_commit_of_file" do
it "gives last revision commit when before_commit is nil" do
expect(
described_class.last_revision_commit_of_file(HOMEBREW_CACHE, file),
).to eq(hash1)
).to eq(file_hash1)
end
it "gives revision commit based on before_commit when it is not nil" do
expect(
described_class.last_revision_commit_of_file(HOMEBREW_CACHE,
file,
before_commit: hash2),
).to eq(hash2)
before_commit: file_hash2),
).to eq(file_hash2)
end
end
describe "#last_revision_commit_of_files" do
context "when before_commit is nil" do
it "gives last revision commit" do
expect(
described_class.last_revision_commit_of_files(HOMEBREW_CACHE, files),
).to eq(files_hash1)
end
end
context "when before_commit is not nil" do
it "gives last revision commit" do
expect(
described_class.last_revision_commit_of_files(HOMEBREW_CACHE,
files,
before_commit: file_hash2),
).to eq(files_hash2)
end
end
end
@ -46,14 +78,14 @@ describe Git do
expect(
described_class.last_revision_of_file(HOMEBREW_CACHE,
HOMEBREW_CACHE/file),
).to eq("blah")
).to eq("README")
end
it "returns last revision of file based on before_commit" do
expect(
described_class.last_revision_of_file(HOMEBREW_CACHE, HOMEBREW_CACHE/file,
before_commit: "0..3"),
).to eq("brew")
).to eq("# README")
end
end
end

View File

@ -471,6 +471,13 @@ module GitHub
scopes: CREATE_ISSUE_FORK_OR_PR_SCOPES)
end
def workflow_dispatch_event(user, repo, workflow, ref, **inputs)
url = "#{API_URL}/repos/#{user}/#{repo}/actions/workflows/#{workflow}/dispatches"
open_api(url, data: { ref: ref, inputs: inputs },
request_method: :POST,
scopes: CREATE_ISSUE_FORK_OR_PR_SCOPES)
end
def get_artifact_url(user, repo, pr, workflow_id: "tests.yml", artifact_name: "bottles")
scopes = CREATE_ISSUE_FORK_OR_PR_SCOPES
base_url = "#{API_URL}/repos/#{user}/#{repo}"

View File

@ -16,6 +16,11 @@ class User < DelegateClass(String)
end
def self.current
@current ||= new(Etc.getpwuid(Process.euid).name)
return @current if defined?(@current)
pwuid = Etc.getpwuid(Process.euid)
return if pwuid.nil?
@current = new(pwuid.name)
end
end

View File

@ -4,29 +4,31 @@ ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
ruby_version = RbConfig::CONFIG["ruby_version"]
path = File.expand_path('..', __FILE__)
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.8.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.8.4/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.14.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thread_safe-0.3.6/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-1.2.7/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.3.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.4.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.0.3.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.7/lib"
$:.unshift "#{path}/"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/byebug-11.1.3"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/byebug-11.1.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/colorize-0.8.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/json-2.3.1"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/json-2.3.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/docile-1.3.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.18.5/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/url-0.3.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/codecov-0.1.17/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/codecov-0.2.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/connection_pool-2.2.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/diff-lcs-1.4.4/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/unf_ext-0.0.7.7"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf_ext-0.0.7.7/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf-0.1.4/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/domain_name-0.5.20190701/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/elftools-1.1.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/hpricot-0.8.6"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/hpricot-0.8.6/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/http-cookie-1.0.3/lib"
@ -44,6 +46,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.19.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.0.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.1.4/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.1.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/rdiscount-2.2.0.1"
@ -59,10 +62,10 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-3.9.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-its-1.3.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-0.1.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-0.2.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.7.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.87.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.6.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.41.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.88.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.7.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.42.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib"

View File

@ -20,7 +20,7 @@ module I18n
# Sets the current fallbacks implementation. Use this to set a different fallbacks implementation.
def fallbacks=(fallbacks)
@@fallbacks = fallbacks
@@fallbacks = fallbacks.is_a?(I18n::Locale::Fallbacks) ? fallbacks : I18n::Locale::Fallbacks.new(fallbacks)
end
end

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