Merge branch 'master' into integrate-uninstall-reinstall

This commit is contained in:
William Ma 2020-06-30 13:33:06 -04:00
commit bb939323a7
49 changed files with 973 additions and 195 deletions

View File

@ -17,7 +17,7 @@ GEM
term-ansicolor (~> 1.3)
thor (>= 0.19.4, < 2.0)
tins (~> 1.6)
diff-lcs (1.4.2)
diff-lcs (1.4.3)
docile (1.3.2)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
@ -26,7 +26,7 @@ GEM
domain_name (~> 0.5)
i18n (1.8.3)
concurrent-ruby (~> 1.0)
json (2.3.0)
json (2.3.1)
mechanize (2.7.6)
domain_name (~> 0.5, >= 0.5.1)
http-cookie (~> 1.0)
@ -91,7 +91,7 @@ GEM
rubocop-ast (>= 0.0.3, < 1.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-ast (0.0.3)
rubocop-ast (0.1.0)
parser (>= 2.7.0.1)
rubocop-performance (1.6.1)
rubocop (>= 0.71.0)
@ -118,7 +118,7 @@ GEM
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
webrobots (0.1.2)
zeitwerk (2.3.0)
zeitwerk (2.3.1)
PLATFORMS
ruby

View File

@ -267,6 +267,7 @@ module Homebrew
# Need to rescue before `FormulaUnavailableError` (superclass of this)
# is handled, as searching for a formula doesn't make sense here (the
# formula was found, but there's a problem with its implementation).
$stderr.puts e.backtrace if Homebrew::EnvConfig.developer?
ofail e.message
rescue FormulaUnavailableError => e
if e.name == "updog"

View File

@ -3,6 +3,7 @@
require "formula"
require "options"
require "cli/parser"
require "commands"
module Homebrew
module_function
@ -20,8 +21,10 @@ module Homebrew
description: "Show options for formulae that are currently installed."
switch "--all",
description: "Show options for all available formulae."
flag "--command=",
description: "Show options for the specified <command>."
switch :debug
conflicts "--installed", "--all"
conflicts "--installed", "--all", "--command"
end
end
@ -32,6 +35,22 @@ module Homebrew
puts_options Formula.to_a.sort
elsif args.installed?
puts_options Formula.installed.sort
elsif !args.command.nil?
path = Commands.path(args.command)
odie "Unknown command: #{args.command}" unless path
cmd_options = if cmd_parser = CLI::Parser.from_cmd_path(path)
cmd_parser.processed_options.map do |short, long, _, desc|
[long || short, desc]
end
else
cmd_comment_options(path)
end
if args.compact?
puts cmd_options.sort.map(&:first) * " "
else
cmd_options.sort.each { |option, desc| puts "#{option}\n\t#{desc}" }
puts
end
elsif args.no_named?
raise FormulaUnspecifiedError
else
@ -39,6 +58,20 @@ module Homebrew
end
end
def cmd_comment_options(cmd_path)
options = []
comment_lines = cmd_path.read.lines.grep(/^#:/)
return options if comment_lines.empty?
# skip the comment's initial usage summary lines
comment_lines.slice(2..-1).each do |line|
if / (?<option>-[-\w]+) +(?<desc>.*)$/ =~ line
options << [option, desc]
end
end
options
end
def puts_options(formulae)
formulae.each do |f|
next if f.options.empty?

View File

@ -168,14 +168,6 @@ module Homebrew
@text.split("\n__END__").first
end
def data?
/^[^#]*\bDATA\b/ =~ @text
end
def end?
/^__END__$/ =~ @text
end
def trailing_newline?
/\Z\n/ =~ @text
end
@ -234,12 +226,6 @@ module Homebrew
end
def audit_file
# TODO: check could be in RuboCop
problem "'DATA' was found, but no '__END__'" if text.data? && !text.end?
# TODO: check could be in RuboCop
problem "'__END__' was found, but 'DATA' is not used" if text.end? && !text.data?
# 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)."
@ -567,6 +553,7 @@ module Homebrew
THROTTLED_DENYLIST = {
"aws-sdk-cpp" => "10",
"awscli@1" => "10",
"balena-cli" => "10",
"quicktype" => "10",
"vim" => "50",
}.freeze

View File

@ -147,7 +147,6 @@ module Homebrew
raise FormulaUnspecifiedError unless formula
tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula)
check_for_duplicate_pull_requests(formula, tap_full_name)
requested_spec, formula_spec = if args.devel?
devel_message = " (devel)"
@ -315,6 +314,8 @@ module Homebrew
new_formula_version = formula_version(formula, requested_spec, new_contents)
check_for_duplicate_pull_requests(formula, tap_full_name, new_formula_version.to_s)
if !new_mirrors && !formula_spec.mirrors.empty?
if args.force?
opoo "#{formula}: Removing all mirrors because a --mirror= argument was not specified."
@ -468,23 +469,26 @@ module Homebrew
end
end
def fetch_pull_requests(formula, tap_full_name)
GitHub.issues_for_formula(formula.name, tap_full_name: tap_full_name).select do |pr|
def fetch_pull_requests(query, tap_full_name, state: nil)
GitHub.issues_for_formula(query, tap_full_name: tap_full_name, state: state).select do |pr|
pr["html_url"].include?("/pull/") &&
/(^|\s)#{Regexp.quote(formula.name)}(:|\s|$)/i =~ pr["title"]
/(^|\s)#{Regexp.quote(query)}(:|\s|$)/i =~ pr["title"]
end
rescue GitHub::RateLimitExceededError => e
opoo e.message
[]
end
def check_for_duplicate_pull_requests(formula, tap_full_name)
pull_requests = fetch_pull_requests(formula, tap_full_name)
return unless pull_requests
return if pull_requests.empty?
def check_for_duplicate_pull_requests(formula, tap_full_name, version)
# check for open requests
pull_requests = fetch_pull_requests(formula.name, tap_full_name, state: "open")
# if we haven't already found open requests, try for an exact match across all requests
pull_requests = fetch_pull_requests("#{formula.name} #{version}", tap_full_name) if pull_requests.blank?
return if pull_requests.blank?
duplicates_message = <<~EOS
These open pull requests may be duplicates:
These pull requests may be duplicates:
#{pull_requests.map { |pr| "#{pr["title"]} #{pr["html_url"]}" }.join("\n")}
EOS
error_message = "Duplicate PRs should not be opened. Use --force to override this error."

View File

@ -360,7 +360,7 @@ class BuildError < RuntimeError
end
def fetch_issues
GitHub.issues_for_formula(formula.name, tap: formula.tap)
GitHub.issues_for_formula(formula.name, tap: formula.tap, state: "open")
rescue GitHub::RateLimitExceededError => e
opoo e.message
[]

View File

@ -27,6 +27,7 @@ class Keg
# patchelf requires that the ELF file have a .dynstr section.
# Skip ELF files that do not have a .dynstr section.
return if ["cannot find section .dynstr", "strange: no string table"].include?(old_rpath)
unless $CHILD_STATUS.success?
raise ErrorDuringExecution.new(cmd_rpath, status: $CHILD_STATUS, output: [[:stderr, old_rpath]])
end
@ -41,15 +42,15 @@ class Keg
new_rpath = rpath.join(":")
cmd = [patchelf, "--force-rpath", "--set-rpath", new_rpath]
if file.with_interpreter?
old_interpreter = Utils.safe_popen_read(patchelf, "--print-interpreter", file).strip
new_interpreter = if File.readable? "#{new_prefix}/lib/ld.so"
"#{new_prefix}/lib/ld.so"
else
old_interpreter.sub old_prefix, new_prefix
end
cmd << "--set-interpreter" << new_interpreter if old_interpreter != new_interpreter
old_interpreter = file.interpreter
new_interpreter = if old_interpreter.nil?
nil
elsif File.readable? "#{new_prefix}/lib/ld.so"
"#{new_prefix}/lib/ld.so"
else
old_interpreter.sub old_prefix, new_prefix
end
cmd << "--set-interpreter" << new_interpreter if old_interpreter != new_interpreter
return if old_rpath == new_rpath && old_interpreter == new_interpreter

View File

@ -35,6 +35,7 @@ module Formulary
begin
mod.module_eval(contents, path)
rescue NameError, ArgumentError, ScriptError => e
$stderr.puts e.backtrace if Homebrew::EnvConfig.developer?
raise FormulaUnreadableError.new(name, e)
end
class_name = class_s(name)

View File

@ -68,28 +68,24 @@ module ELFShim
elf_type == :executable
end
def with_interpreter?
return @with_interpreter if defined? @with_interpreter
def interpreter
return @interpreter if defined? @interpreter
@with_interpreter = if binary_executable?
true
elsif dylib?
if HOMEBREW_PATCHELF_RB
begin
patchelf_patcher.interpreter.present?
rescue PatchELF::PatchError => e
opoo e unless e.to_s.start_with? "No interpreter found"
false
end
elsif which "readelf"
Utils.popen_read("readelf", "-l", to_path).include?(" INTERP ")
elsif which "file"
Utils.popen_read("file", "-L", "-b", to_path).include?(" interpreter ")
else
raise "Please install either readelf (from binutils) or file."
@interpreter = if HOMEBREW_PATCHELF_RB
begin
patchelf_patcher.interpreter
rescue PatchELF::PatchError => e
opoo e unless e.to_s.start_with? "No interpreter found"
nil
end
elsif (patchelf = DevelopmentTools.locate "patchelf")
interp = Utils.popen_read(patchelf, "--print-interpreter", to_s, err: :out).strip
$CHILD_STATUS.success? ? interp : nil
elsif (file = DevelopmentTools.locate("file"))
output = Utils.popen_read(file, "-L", "-b", to_s, err: :out).strip
output[/^ELF.*, interpreter (.+?), /, 1]
else
false
raise "Please install either patchelf or file."
end
end

View File

@ -22,5 +22,6 @@ require "rubocops/uses_from_macos"
require "rubocops/files"
require "rubocops/keg_only"
require "rubocops/version"
require "rubocops/deprecate"
require "rubocops/rubocop-cask"

View File

@ -226,11 +226,10 @@ module RuboCop
next if succeeding_component.empty?
offensive_nodes = check_precedence(preceding_component, succeeding_component)
break if offensive_nodes
return [present_components, offensive_nodes] if offensive_nodes
end
end
[present_components, offensive_nodes]
nil
end
# Method to format message for reporting component precedence violations

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
require "rubocops/extend/formula"
module RuboCop
module Cop
module FormulaAudit
# This cop audits deprecate!
class Deprecate < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
deprecate_node = find_node_method_by_name(body_node, :deprecate!)
return if deprecate_node.nil? || deprecate_node.children.length < 3
date_node = find_strings(deprecate_node).first
begin
Date.iso8601(string_content(date_node))
rescue ArgumentError
fixed_date_string = Date.parse(string_content(date_node)).iso8601
offending_node(date_node)
problem "Use `#{fixed_date_string}` to comply with ISO 8601"
end
end
def autocorrect(node)
lambda do |corrector|
fixed_fixed_date_string = Date.parse(string_content(node)).iso8601
corrector.replace(node.source_range, "\"#{fixed_fixed_date_string}\"")
end
end
end
end
end
end

View File

@ -195,7 +195,7 @@ module RuboCop
end
end
class ShellCmd < FormulaCop
class SafePopenCommands < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
test = find_block(body_node, :test)
@ -223,6 +223,35 @@ module RuboCop
end
end
class ShellVariables < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
popen_commands = [
:popen,
:popen_read,
:safe_popen_read,
:popen_write,
:safe_popen_write,
]
popen_commands.each do |command|
find_instance_method_call(body_node, "Utils", command) do |method|
next unless match = regex_match_group(parameters(method).first, /^([^"' ]+)=([^"' ]+)(?: (.*))?$/)
good_args = "Utils.#{command}({ \"#{match[1]}\" => \"#{match[2]}\" }, \"#{match[3]}\")"
problem "Use `#{good_args}` instead of `#{method.source}`"
end
end
end
def autocorrect(node)
lambda do |corrector|
match = regex_match_group(node, /^([^"' ]+)=([^"' ]+)(?: (.*))?$/)
corrector.replace(node.source_range, "{ \"#{match[1]}\" => \"#{match[2]}\" }, \"#{match[3]}\"")
end
end
end
class Miscellaneous < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
# FileUtils is included in Formula

View File

@ -8,7 +8,9 @@ module RuboCop
module FormulaAudit
# This cop audits patches in Formulae.
class Patches < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body)
def audit_formula(node, _class_node, _parent_class_node, body)
@full_source_content = source_buffer(node).source
external_patches = find_all_blocks(body, :patch)
external_patches.each do |patch_block|
url_node = find_every_method_call_by_name(patch_block, :url).first
@ -16,6 +18,14 @@ module RuboCop
patch_problems(url_string)
end
inline_patches = find_every_method_call_by_name(body, :patch)
inline_patches.each { |patch| inline_patch_problems(patch) }
if inline_patches.empty? && patch_end?
offending_patch_end_node(node)
problem "patch is missing 'DATA'"
end
patches_node = find_method_def(body, :patches)
return if patches_node.nil?
@ -84,6 +94,30 @@ module RuboCop
#{patch_url}
EOS
end
def inline_patch_problems(patch)
return unless patch_data?(patch) && !patch_end?
offending_node(patch)
problem "patch is missing '__END__'"
end
def_node_search :patch_data?, <<~AST
(send nil? :patch (:sym :DATA))
AST
def patch_end?
/^__END__$/.match?(@full_source_content)
end
def offending_patch_end_node(node)
@offensive_node = node
@source_buf = source_buffer(node)
@line_no = node.loc.last_line + 1
@column = 0
@length = 7 # "__END__".size
@offense_source_range = source_range(@source_buf, @line_no, @column, @length)
end
end
end
end

View File

@ -115,6 +115,8 @@ class SoftwareSpec
raise DuplicateResourceError, name if resource_defined?(name)
res = klass.new(name, &block)
return unless res.url
resources[name] = res
dependency_collector.add(res)
else

View File

@ -652,6 +652,7 @@ false:
- ./test/rubocops/components_redundancy_spec.rb
- ./test/rubocops/conflicts_spec.rb
- ./test/rubocops/dependency_order_spec.rb
- ./test/rubocops/deprecate_spec.rb
- ./test/rubocops/formula_desc_spec.rb
- ./test/rubocops/homepage_spec.rb
- ./test/rubocops/lines_spec.rb
@ -884,6 +885,7 @@ true:
- ./rubocops/cask/ast/stanza.rb
- ./rubocops/cask/constants/stanza.rb
- ./rubocops/cask/extend/string.rb
- ./rubocops/deprecate.rb
- ./tap_constants.rb
- ./test/support/helper/fixtures.rb
- ./test/support/lib/config.rb

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
@ -344,6 +344,28 @@ class RuboCop::AST::IfNode < ::RuboCop::AST::Node
def unless?; end
end
class RuboCop::AST::IndexNode < ::RuboCop::AST::Node
include(::RuboCop::AST::ParameterizedNode)
include(::RuboCop::AST::MethodIdentifierPredicates)
include(::RuboCop::AST::MethodDispatchNode)
def arguments; end
def assignment_method?; end
def attribute_accessor?; end
def method_name; end
end
class RuboCop::AST::IndexasgnNode < ::RuboCop::AST::Node
include(::RuboCop::AST::ParameterizedNode)
include(::RuboCop::AST::MethodIdentifierPredicates)
include(::RuboCop::AST::MethodDispatchNode)
def arguments; end
def assignment_method?; end
def attribute_accessor?; end
def method_name; end
end
class RuboCop::AST::IntNode < ::RuboCop::AST::Node
include(::RuboCop::AST::NumericNode)
end
@ -359,6 +381,19 @@ end
RuboCop::AST::KeywordSplatNode::DOUBLE_SPLAT = T.let(T.unsafe(nil), String)
class RuboCop::AST::LambdaNode < ::RuboCop::AST::Node
include(::RuboCop::AST::ParameterizedNode)
include(::RuboCop::AST::MethodIdentifierPredicates)
include(::RuboCop::AST::MethodDispatchNode)
def arguments; end
def assignment_method?; end
def attribute_accessor?; end
def lambda?; end
def lambda_literal?; end
def method_name; end
end
module RuboCop::AST::MethodDispatchNode
include(::RuboCop::AST::MethodIdentifierPredicates)
extend(::RuboCop::AST::NodePattern::Macros)
@ -409,9 +444,16 @@ module RuboCop::AST::MethodIdentifierPredicates
def camel_case_method?; end
def comparison_method?; end
def const_receiver?; end
def enumerable_method?; end
def enumerator_method?; end
def method?(name); end
def negation_method?; end
def nonmutating_array_method?; end
def nonmutating_binary_operator_method?; end
def nonmutating_hash_method?; end
def nonmutating_operator_method?; end
def nonmutating_string_method?; end
def nonmutating_unary_operator_method?; end
def operator_method?; end
def predicate_method?; end
def prefix_bang?; end
@ -419,9 +461,23 @@ module RuboCop::AST::MethodIdentifierPredicates
def self_receiver?; end
end
RuboCop::AST::MethodIdentifierPredicates::ENUMERATOR_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::AST::MethodIdentifierPredicates::ENUMERABLE_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::OPERATOR_METHODS = T.let(T.unsafe(nil), Array)
RuboCop::AST::MethodIdentifierPredicates::ENUMERATOR_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::NONMUTATING_ARRAY_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::NONMUTATING_BINARY_OPERATOR_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::NONMUTATING_HASH_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::NONMUTATING_OPERATOR_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::NONMUTATING_STRING_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::NONMUTATING_UNARY_OPERATOR_METHODS = T.let(T.unsafe(nil), Set)
RuboCop::AST::MethodIdentifierPredicates::OPERATOR_METHODS = T.let(T.unsafe(nil), Set)
module RuboCop::AST::ModifierNode
def modifier_form?; end
@ -450,6 +506,7 @@ class RuboCop::AST::Node < ::Parser::AST::Node
def arg_type?; end
def args_type?; end
def argument?; end
def argument_type?; end
def array_pattern_type?; end
def array_pattern_with_tail_type?; end
def array_type?; end
@ -506,9 +563,11 @@ class RuboCop::AST::Node < ::Parser::AST::Node
def erange_type?; end
def false_type?; end
def falsey_literal?; end
def find_pattern_type?; end
def first_line; end
def float_type?; end
def for_type?; end
def forward_arg_type?; end
def forward_args_type?; end
def forwarded_args_type?; end
def guard_clause?; end
@ -542,6 +601,7 @@ class RuboCop::AST::Node < ::Parser::AST::Node
def last_line; end
def line_count; end
def literal?; end
def loop_keyword?; end
def lvar_type?; end
def lvasgn_type?; end
def masgn_type?; end
@ -582,6 +642,7 @@ class RuboCop::AST::Node < ::Parser::AST::Node
def parent_module_name; end
def parenthesized_call?; end
def pin_type?; end
def post_condition_loop?; end
def postexe_type?; end
def preexe_type?; end
def proc?(node = _); end
@ -654,6 +715,8 @@ class RuboCop::AST::Node < ::Parser::AST::Node
def while_until_value_used?; end
end
RuboCop::AST::Node::ARGUMENT_TYPES = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::ASSIGNMENTS = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::BASIC_CONDITIONALS = T.let(T.unsafe(nil), Array)
@ -676,10 +739,14 @@ RuboCop::AST::Node::KEYWORDS = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::LITERALS = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::LOOP_TYPES = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::MUTABLE_LITERALS = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::OPERATOR_KEYWORDS = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::POST_CONDITION_LOOP_TYPES = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::REFERENCES = T.let(T.unsafe(nil), Array)
RuboCop::AST::Node::SHORTHAND_ASSIGNMENTS = T.let(T.unsafe(nil), Array)
@ -697,7 +764,7 @@ class RuboCop::AST::NodePattern
def eql?(other); end
def marshal_dump; end
def marshal_load(pattern); end
def match(*args); end
def match(*args, **rest); end
def pattern; end
def to_s; end
@ -708,12 +775,8 @@ class RuboCop::AST::NodePattern::Invalid < ::StandardError
end
module RuboCop::AST::NodePattern::Macros
def def_node_matcher(method_name, pattern_str); end
def def_node_search(method_name, pattern_str); end
def node_search(method_name, compiler, on_match, prelude, called_from); end
def node_search_all(method_name, compiler, called_from); end
def node_search_body(method_name, trailing_params, prelude, match_code, on_match); end
def node_search_first(method_name, compiler, called_from); end
def def_node_matcher(method_name, pattern_str, **keyword_defaults); end
def def_node_search(method_name, pattern_str, **keyword_defaults); end
end
module RuboCop::AST::NumericNode
@ -825,8 +888,22 @@ end
class RuboCop::AST::RegexpNode < ::RuboCop::AST::Node
def content; end
def delimiter?(char); end
def delimiters; end
def extended?; end
def ignore_case?; end
def interpolation?; end
def multiline_mode?; end
def no_encoding?; end
def percent_r_literal?; end
def regopt; end
def single_interpolation?; end
def slash_literal?; end
def to_regexp; end
private
def regopt_include?(option); end
end
RuboCop::AST::RegexpNode::OPTIONS = T.let(T.unsafe(nil), Hash)
@ -920,6 +997,7 @@ class RuboCop::AST::Token
end
module RuboCop::AST::Traversal
def on___ENCODING__(node); end
def on_alias(node); end
def on_and(node); end
def on_and_asgn(node); end
@ -958,6 +1036,7 @@ module RuboCop::AST::Traversal
def on_false(node); end
def on_float(node); end
def on_for(node); end
def on_forward_arg(node); end
def on_forward_args(node); end
def on_forwarded_args(node); end
def on_gvar(node); end
@ -969,6 +1048,8 @@ module RuboCop::AST::Traversal
def on_iflipflop(node); end
def on_in_match(node); end
def on_in_pattern(node); end
def on_index(node); end
def on_indexasgn(node); end
def on_int(node); end
def on_irange(node); end
def on_ivar(node); end
@ -1005,6 +1086,7 @@ module RuboCop::AST::Traversal
def on_pin(node); end
def on_postexe(node); end
def on_preexe(node); end
def on_procarg0(node); end
def on_rational(node); end
def on_redo(node); end
def on_regexp(node); end
@ -1095,6 +1177,8 @@ RuboCop::AST::NodePattern::Compiler::CAPTURED_REST = T.let(T.unsafe(nil), String
RuboCop::AST::NodePattern::Compiler::CLOSING = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::CONST = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::CUR_ELEMENT = T.let(T.unsafe(nil), String)
RuboCop::AST::NodePattern::Compiler::CUR_NODE = T.let(T.unsafe(nil), String)
@ -1105,6 +1189,10 @@ RuboCop::AST::NodePattern::Compiler::FUNCALL = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::IDENTIFIER = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::KEYWORD = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::KEYWORD_NAME = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::LITERAL = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::META = T.let(T.unsafe(nil), Regexp)
@ -1117,6 +1205,8 @@ RuboCop::AST::NodePattern::Compiler::NUMBER = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::PARAM = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::PARAM_CONST = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::PARAM_NUMBER = T.let(T.unsafe(nil), Regexp)
RuboCop::AST::NodePattern::Compiler::PREDICATE = T.let(T.unsafe(nil), Regexp)

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

@ -19429,10 +19429,6 @@ class RuboCop::AST::Node
def cask_block?(node=T.unsafe(nil)); end
def find_pattern_type?(); end
def forward_arg_type?(); end
def key_node(node=T.unsafe(nil)); end
def method_node(node=T.unsafe(nil)); end
@ -19604,6 +19600,10 @@ class RuboCop::Cop::FormulaAudit::Miscellaneous
def languageNodeModule?(node0); end
end
class RuboCop::Cop::FormulaAudit::Patches
def patch_data?(node0); end
end
class RuboCop::Cop::FormulaAudit::Test
def test_calls(node0); end
end

View File

@ -71,9 +71,82 @@ describe Cask::Cmd::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
end
it 'updates "auto_updates" and "latest" Casks when their tokens are provided in the command line' do
local_caffeine = Cask::CaskLoader.load("local-caffeine")
local_caffeine_path = Cask::Config.global.appdir.join("Caffeine.app")
auto_updates = Cask::CaskLoader.load("auto-updates")
auto_updates_path = Cask::Config.global.appdir.join("MyFancyApp.app")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57")
described_class.run("local-caffeine", "auto-updates")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.3")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.61")
end
end
describe "with --greedy it checks additional Casks" do
it 'includes the Casks with "auto_updates true" or "version latest"' do
local_caffeine = Cask::CaskLoader.load("local-caffeine")
local_caffeine_path = Cask::Config.global.appdir.join("Caffeine.app")
auto_updates = Cask::CaskLoader.load("auto-updates")
auto_updates_path = Cask::Config.global.appdir.join("MyFancyApp.app")
local_transmission = Cask::CaskLoader.load("local-transmission")
local_transmission_path = Cask::Config.global.appdir.join("Transmission.app")
version_latest = Cask::CaskLoader.load("version-latest")
version_latest_path_1 = Cask::Config.global.appdir.join("Caffeine Mini.app")
version_latest_path_2 = Cask::Config.global.appdir.join("Caffeine Pro.app")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
expect(version_latest).to be_installed
expect(version_latest_path_1).to be_a_directory
expect(version_latest_path_2).to be_a_directory
expect(version_latest.versions).to include("latest")
described_class.run("--greedy")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.3")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.61")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.61")
expect(version_latest).to be_installed
expect(version_latest_path_1).to be_a_directory
expect(version_latest_path_2).to be_a_directory
expect(version_latest.versions).to include("latest")
end
it 'does not include the Casks with "auto_updates true" when the version did not change' do
cask = Cask::CaskLoader.load("auto-updates")
cask_path = cask.config.appdir.join("MyFancyApp.app")
@ -97,6 +170,179 @@ describe Cask::Cmd::Upgrade, :cask do
end
end
context "dry run upgrade" do
let(:installed) {
[
"outdated/local-caffeine",
"outdated/local-transmission",
"outdated/auto-updates",
"outdated/version-latest",
]
}
before do
installed.each { |cask| Cask::Cmd::Install.run(cask) }
allow_any_instance_of(described_class).to receive(:verbose?).and_return(true)
end
describe 'without --greedy it ignores the Casks with "version latest" or "auto_updates true"' do
it "would update all the installed Casks when no token is provided" do
local_caffeine = Cask::CaskLoader.load("local-caffeine")
local_caffeine_path = Cask::Config.global.appdir.join("Caffeine.app")
local_transmission = Cask::CaskLoader.load("local-transmission")
local_transmission_path = Cask::Config.global.appdir.join("Transmission.app")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
described_class.run("--dry-run")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(local_caffeine.versions).not_to include("1.2.3")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
expect(local_transmission.versions).not_to include("2.61")
end
it "would update only the Casks specified in the command line" do
local_caffeine = Cask::CaskLoader.load("local-caffeine")
local_caffeine_path = Cask::Config.global.appdir.join("Caffeine.app")
local_transmission = Cask::CaskLoader.load("local-transmission")
local_transmission_path = Cask::Config.global.appdir.join("Transmission.app")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
described_class.run("--dry-run", "local-caffeine")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(local_caffeine.versions).not_to include("1.2.3")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
expect(local_transmission.versions).not_to include("2.61")
end
it 'would update "auto_updates" and "latest" Casks when their tokens are provided in the command line' do
local_caffeine = Cask::CaskLoader.load("local-caffeine")
local_caffeine_path = Cask::Config.global.appdir.join("Caffeine.app")
auto_updates = Cask::CaskLoader.load("auto-updates")
auto_updates_path = Cask::Config.global.appdir.join("MyFancyApp.app")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57")
described_class.run("--dry-run", "local-caffeine", "auto-updates")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(local_caffeine.versions).not_to include("1.2.3")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57")
expect(auto_updates.versions).not_to include("2.61")
end
end
describe "with --greedy it checks additional Casks" do
it 'would include the Casks with "auto_updates true" or "version latest"' do
local_caffeine = Cask::CaskLoader.load("local-caffeine")
local_caffeine_path = Cask::Config.global.appdir.join("Caffeine.app")
auto_updates = Cask::CaskLoader.load("auto-updates")
auto_updates_path = Cask::Config.global.appdir.join("MyFancyApp.app")
local_transmission = Cask::CaskLoader.load("local-transmission")
local_transmission_path = Cask::Config.global.appdir.join("Transmission.app")
version_latest = Cask::CaskLoader.load("version-latest")
version_latest_path_1 = Cask::Config.global.appdir.join("Caffeine Mini.app")
version_latest_path_2 = Cask::Config.global.appdir.join("Caffeine Pro.app")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
expect(version_latest).to be_installed
expect(version_latest_path_1).to be_a_directory
expect(version_latest.versions).to include("latest")
described_class.run("--greedy", "--dry-run")
expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2")
expect(local_caffeine.versions).not_to include("1.2.3")
expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57")
expect(auto_updates.versions).not_to include("2.61")
expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60")
expect(local_transmission.versions).not_to include("2.61")
expect(version_latest).to be_installed
expect(version_latest_path_2).to be_a_directory
end
it 'does not include the Casks with "auto_updates true" when the version did not change' do
cask = Cask::CaskLoader.load("auto-updates")
cask_path = cask.config.appdir.join("MyFancyApp.app")
expect(cask).to be_installed
expect(cask_path).to be_a_directory
expect(cask.versions).to include("2.57")
described_class.run("--dry-run", "auto-updates", "--greedy")
expect(cask).to be_installed
expect(cask_path).to be_a_directory
expect(cask.versions).to include("2.57")
expect(cask.versions).not_to include("2.61")
described_class.run("--dry-run", "auto-updates", "--greedy")
expect(cask).to be_installed
expect(cask_path).to be_a_directory
expect(cask.versions).to include("2.57")
expect(cask.versions).not_to include("2.61")
end
end
end
context "failed upgrade" do
let(:installed) {
[

View File

@ -6,6 +6,34 @@ describe Cask::Pkg, :cask do
let(:empty_response) { double(stdout: "", plist: { "volume" => "/", "install-location" => "", "paths" => {} }) }
let(:pkg) { described_class.new("my.fake.pkg", fake_system_command) }
it "removes files and dirs referenced by the pkg" do
some_files = Array.new(3) { Pathname.new(Tempfile.new("plain_file").path) }
allow(pkg).to receive(:pkgutil_bom_files).and_return(some_files)
some_specials = Array.new(3) { Pathname.new(Tempfile.new("special_file").path) }
allow(pkg).to receive(:pkgutil_bom_specials).and_return(some_specials)
some_dirs = Array.new(3) { mktmpdir }
allow(pkg).to receive(:pkgutil_bom_dirs).and_return(some_dirs)
root_dir = Pathname.new(mktmpdir)
allow(pkg).to receive(:root).and_return(root_dir)
allow(pkg).to receive(:forget)
pkg.uninstall
some_files.each do |file|
expect(file).not_to exist
end
some_dirs.each do |dir|
expect(dir).not_to exist
end
expect(root_dir).not_to exist
end
context "pkgutil" do
it "forgets the pkg" do
allow(fake_system_command).to receive(:run!).with(

View File

@ -41,8 +41,6 @@ module Homebrew
url "https://www.brew.sh/valid-1.0.tar.gz"
RUBY
expect(ft).not_to have_data
expect(ft).not_to have_end
expect(ft).to have_trailing_newline
expect(ft =~ /\burl\b/).to be_truthy
@ -55,20 +53,6 @@ module Homebrew
ft = formula_text "newline"
expect(ft).to have_trailing_newline
end
specify "#data?" do
ft = formula_text "data", <<~RUBY
patch :DATA
RUBY
expect(ft).to have_data
end
specify "#end?" do
ft = formula_text "end", "", patch: "__END__\na patch here"
expect(ft).to have_end
expect(ft.without_patch).to eq("class End < Formula\n \nend")
end
end
describe FormulaAuditor do
@ -96,31 +80,6 @@ module Homebrew
end
describe "#audit_file" do
specify "DATA but no __END__" do
fa = formula_auditor "foo", <<~RUBY
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
patch :DATA
end
RUBY
fa.audit_file
expect(fa.problems).to eq(["'DATA' was found, but no '__END__'"])
end
specify "__END__ but no DATA" do
fa = formula_auditor "foo", <<~RUBY
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
end
__END__
a patch goes here
RUBY
fa.audit_file
expect(fa.problems).to eq(["'__END__' was found, but 'DATA' is not used"])
end
specify "no issue" do
fa = formula_auditor "foo", <<~RUBY
class Foo < Formula

View File

@ -77,6 +77,37 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do
RUBY
end
it "When `install` precedes `depends_on`" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
def install
end
depends_on "openssl"
^^^^^^^^^^^^^^^^^^^^ `depends_on` (line 7) should be put before `install` (line 4)
end
RUBY
end
it "When `test` precedes `depends_on`" do
expect_offense(<<~RUBY)
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"
def install
end
def test
end
depends_on "openssl"
^^^^^^^^^^^^^^^^^^^^ `depends_on` (line 10) should be put before `install` (line 4)
end
RUBY
end
it "When only one of many `depends_on` precedes `conflicts_with`" do
expect_offense(<<~RUBY)
class Foo < Formula

View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
require "rubocops/deprecate"
describe RuboCop::Cop::FormulaAudit::Deprecate do
subject(:cop) { described_class.new }
context "When auditing formula for deprecate!" do
it "deprecation date is not ISO 8601 compliant" do
expect_offense(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
deprecate! :date => "June 25, 2020"
^^^^^^^^^^^^^^^ Use `2020-06-25` to comply with ISO 8601
end
RUBY
end
it "deprecation date is ISO 8601 compliant" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
deprecate! :date => "2020-06-25"
end
RUBY
end
it "no deprecation date" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
deprecate!
end
RUBY
end
it "auto corrects to ISO 8601 format" do
source = <<~RUBY
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
deprecate! :date => "June 25, 2020"
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
deprecate! :date => "2020-06-25"
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
end
end

View File

@ -345,10 +345,10 @@ describe RuboCop::Cop::FormulaAudit::MpiCheck do
end
end
describe RuboCop::Cop::FormulaAudit::ShellCmd do
describe RuboCop::Cop::FormulaAudit::SafePopenCommands do
subject(:cop) { described_class.new }
context "When auditing shell commands" do
context "When auditing popen commands" do
it "Utils.popen_read should become Utils.safe_popen_read" do
expect_offense(<<~RUBY)
class Foo < Formula
@ -440,6 +440,140 @@ describe RuboCop::Cop::FormulaAudit::ShellCmd do
end
end
describe RuboCop::Cop::FormulaAudit::ShellVariables do
subject(:cop) { described_class.new }
context "When auditing shell variables" do
it "Shell variables should be expanded in Utils.popen" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
Utils.popen "SHELL=bash foo"
^^^^^^^^^^^^^^ Use `Utils.popen({ "SHELL" => "bash" }, "foo")` instead of `Utils.popen "SHELL=bash foo"`
end
end
RUBY
end
it "Shell variables should be expanded in Utils.safe_popen_read" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
Utils.safe_popen_read "SHELL=bash foo"
^^^^^^^^^^^^^^ Use `Utils.safe_popen_read({ "SHELL" => "bash" }, "foo")` instead of `Utils.safe_popen_read "SHELL=bash foo"`
end
end
RUBY
end
it "Shell variables should be expanded in Utils.safe_popen_write" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
Utils.safe_popen_write "SHELL=bash foo"
^^^^^^^^^^^^^^ Use `Utils.safe_popen_write({ "SHELL" => "bash" }, "foo")` instead of `Utils.safe_popen_write "SHELL=bash foo"`
end
end
RUBY
end
it "Shell variables should be expanded and keep inline string variables in the arguments" do
expect_offense(<<~RUBY)
class Foo < Formula
def install
Utils.popen "SHELL=bash \#{bin}/foo"
^^^^^^^^^^^^^^^^^^^^^ Use `Utils.popen({ "SHELL" => "bash" }, "\#{bin}/foo")` instead of `Utils.popen "SHELL=bash \#{bin}/foo"`
end
end
RUBY
end
it "corrects shell variables in Utils.popen" do
source = <<~RUBY
class Foo < Formula
def install
Utils.popen("SHELL=bash foo")
end
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
def install
Utils.popen({ "SHELL" => "bash" }, "foo")
end
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
it "corrects shell variables in Utils.safe_popen_read" do
source = <<~RUBY
class Foo < Formula
def install
Utils.safe_popen_read("SHELL=bash foo")
end
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
def install
Utils.safe_popen_read({ "SHELL" => "bash" }, "foo")
end
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
it "corrects shell variables in Utils.safe_popen_write" do
source = <<~RUBY
class Foo < Formula
def install
Utils.safe_popen_write("SHELL=bash foo")
end
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
def install
Utils.safe_popen_write({ "SHELL" => "bash" }, "foo")
end
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
it "corrects shell variables with inline string variable in arguments" do
source = <<~RUBY
class Foo < Formula
def install
Utils.popen("SHELL=bash \#{bin}/foo")
end
end
RUBY
corrected_source = <<~RUBY
class Foo < Formula
def install
Utils.popen({ "SHELL" => "bash" }, "\#{bin}/foo")
end
end
RUBY
new_source = autocorrect_source(source)
expect(new_source).to eq(corrected_source)
end
end
end
describe RuboCop::Cop::FormulaAudit::Miscellaneous do
subject(:cop) { described_class.new }

View File

@ -163,6 +163,53 @@ describe RuboCop::Cop::FormulaAudit::Patches do
end
end
context "When auditing inline patches" do
it "reports no offenses for valid inline patches" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
patch :DATA
end
__END__
patch content here
RUBY
end
it "reports no offenses for valid nested inline patches" do
expect_no_offenses(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
stable do
patch :DATA
end
end
__END__
patch content here
RUBY
end
it "reports an offense when DATA is found with no __END__" do
expect_offense(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
patch :DATA
^^^^^^^^^^^ patch is missing '__END__'
end
RUBY
end
it "reports an offense when __END__ is found with no DATA" do
expect_offense(<<~RUBY)
class Foo < Formula
url 'https://brew.sh/foo-1.0.tgz'
end
__END__
^^^^^^^ patch is missing 'DATA'
patch content here
RUBY
end
end
context "When auditing external patches" do
it "Patch URLs" do
patch_urls = [

View File

@ -78,6 +78,17 @@ RSpec.configure do |config|
c.max_formatted_output_length = 200
end
# Use rspec-retry in CI.
if ENV["CI"]
config.verbose_retry = true
config.display_try_failure_messages = true
config.default_retry_count = 2
config.around(:each, :needs_network) do |example|
example.run_with_retry retry: 3, retry_wait: 3
end
end
# Never truncate output objects.
RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = nil
@ -124,10 +135,6 @@ RSpec.configure do |config|
skip "Requires network connection." unless ENV["HOMEBREW_TEST_ONLINE"]
end
config.around(:each, :needs_network) do |example|
example.run_with_retry retry: 3, retry_wait: 1
end
config.before(:each, :needs_svn) do
skip "subversion not installed." unless quiet_system "#{HOMEBREW_SHIMS_PATH}/scm/svn", "--version"

View File

@ -173,6 +173,16 @@ describe Version do
expect(versions.sort_by { |v| described_class.create(v) }).to eq(versions)
end
describe "#empty?" do
it "returns true if version is empty" do
expect(described_class.create("").empty?).to eq(true)
end
it "returns false if version is not empty" do
expect(described_class.create("1.2.3").empty?).to eq(false)
end
end
specify "hash equality" do
v1 = described_class.create("0.1.0")
v2 = described_class.create("0.1.0")

View File

@ -293,10 +293,8 @@ module GitHub
search("code", **qualifiers)
end
def issues_for_formula(name, options = {})
tap = options[:tap] || CoreTap.instance
tap_full_name = options[:tap_full_name] || tap.full_name
search_issues(name, state: "open", repo: tap_full_name, in: "title")
def issues_for_formula(name, tap: CoreTap.instance, tap_full_name: tap.full_name, state: nil)
search_issues(name, repo: tap_full_name, state: state, in: "title")
end
def user

View File

@ -8,7 +8,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.8.3/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.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.3.1/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}/"
@ -25,7 +25,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tins-1.25.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/term-ansicolor-1.7.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/coveralls-0.8.23/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/diff-lcs-1.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/diff-lcs-1.4.2/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"
@ -62,7 +62,7 @@ $:.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.0.3/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-0.1.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.86.0/lib"

View File

@ -1,33 +0,0 @@
# frozen_string_literal: true
module Kernel
module_function
# We cannot decorate with prepend + super because Kernel has already been
# included in Object, and changes in ancestors don't get propagated into
# already existing ancestor chains.
alias_method :zeitwerk_original_require, :require
# @param path [String]
# @return [Boolean]
def require(path)
if loader = Zeitwerk::Registry.loader_for(path)
if path.end_with?(".rb")
zeitwerk_original_require(path).tap do |required|
loader.on_file_autoloaded(path) if required
end
else
loader.on_dir_autoloaded(path)
end
else
zeitwerk_original_require(path).tap do |required|
if required
realpath = $LOADED_FEATURES.last
if loader = Zeitwerk::Registry.loader_for(realpath)
loader.on_file_autoloaded(realpath)
end
end
end
end
end
end

View File

@ -0,0 +1,64 @@
# frozen_string_literal: true
module Kernel
module_function
# We are going to decorate Kerner#require with two goals.
#
# First, by intercepting Kernel#require calls, we are able to autovivify
# modules on required directories, and also do internal housekeeping when
# managed files are loaded.
#
# On the other hand, if you publish a new version of a gem that is now managed
# by Zeitwerk, client code can reference directly your classes and modules and
# should not require anything. But if someone has legacy require calls around,
# they will work as expected, and in a compatible way.
#
# We cannot decorate with prepend + super because Kernel has already been
# included in Object, and changes in ancestors don't get propagated into
# already existing ancestor chains.
alias_method :zeitwerk_original_require, :require
# @param path [String]
# @return [Boolean]
def require(path)
if loader = Zeitwerk::Registry.loader_for(path)
if path.end_with?(".rb")
zeitwerk_original_require(path).tap do |required|
loader.on_file_autoloaded(path) if required
end
else
loader.on_dir_autoloaded(path)
end
else
zeitwerk_original_require(path).tap do |required|
if required
realpath = $LOADED_FEATURES.last
if loader = Zeitwerk::Registry.loader_for(realpath)
loader.on_file_autoloaded(realpath)
end
end
end
end
end
# By now, I have seen no way so far to decorate require_relative.
#
# For starters, at least in CRuby, require_relative does not delegate to
# require. Both require and require_relative delegate the bulk of their work
# to an internal C function called rb_require_safe. So, our require wrapper is
# not executed.
#
# On the other hand, we cannot use the aliasing technique above because
# require_relative receives a path relative to the directory of the file in
# which the call is performed. If a wrapper here invoked the original method,
# Ruby would resolve the relative path taking lib/zeitwerk as base directory.
#
# A workaround could be to extract the base directory from caller_locations,
# but what if someone else decorated require_relative before us? You can't
# really know with certainty where's the original call site in the stack.
#
# However, the main use case for require_relative is to load files from your
# own project. Projects managed by Zeitwerk don't do this for files managed by
# Zeitwerk, precisely.
end

View File

@ -464,7 +464,7 @@ module Zeitwerk
# require "zeitwerk"
# loader = Zeitwerk::Loader.new
# loader.tag = File.basename(__FILE__, ".rb")
# loader.inflector = Zeitwerk::GemInflector.new
# loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
# loader.push_dir(__dir__)
#
# except that this method returns the same object in subsequent calls from
@ -616,7 +616,10 @@ module Zeitwerk
# $LOADED_FEATURES stores real paths since Ruby 2.4.4. We set and save the
# real path to be able to delete it from $LOADED_FEATURES on unload, and to
# be able to do a lookup later in Kernel#require for manual require calls.
realpath = File.realpath(abspath)
#
# We freeze realpath because that saves allocations in Module#autoload.
# See #125.
realpath = File.realpath(abspath).freeze
parent.autoload(cname, realpath)
if logger
if ruby?(realpath)
@ -719,8 +722,13 @@ module Zeitwerk
def ls(dir)
Dir.foreach(dir) do |basename|
next if basename.start_with?(".")
abspath = File.join(dir, basename)
yield basename, abspath unless ignored_paths.member?(abspath)
next if ignored_paths.member?(abspath)
# We freeze abspath because that saves allocations when passed later to
# File methods. See #125.
yield basename, abspath.freeze
end
end

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true
module Zeitwerk
VERSION = "2.3.0"
VERSION = "2.3.1"
end

View File

@ -429,6 +429,10 @@ class Version
end
alias eql? ==
def empty?
version.empty?
end
def hash
version.hash
end

View File

@ -45,20 +45,19 @@ __brew_completion_caching_policy() {
tmp=( $1(mw-2N) )
(( $#tmp )) || return 0
# otherwise, invalidate if latest tap index file is missing or newer than
# cache file
# otherwise, invalidate if latest tap index file is missing or newer than cache file
tmp=( ${HOMEBREW_REPOSITORY:-/usr/local/Homebrew}/Library/Taps/*/*/.git/index(om[1]N) )
[[ -z $tmp || $tmp -nt $1 ]]
}
__brew_formulae() {
local -a formulae
local -a list
local comp_cachename=brew_formulae
if _cache_invalid $comp_cachename || ! _retrieve_cache $comp_cachename; then
formulae=($(brew search))
_store_cache $comp_cachename formulae
if ! _retrieve_cache $comp_cachename; then
list=( $(brew search) )
_store_cache $comp_cachename list
fi
_describe -t formulae 'all formulae' formulae
_describe -t formulae 'all formulae' list
}
__brew_installed_formulae() {
@ -145,18 +144,17 @@ __brew_common_commands() {
}
__brew_all_commands() {
local -a commands
local -a list
local comp_cachename=brew_all_commands
if _cache_invalid $comp_cachename || ! _retrieve_cache $comp_cachename; then
HOMEBREW_CACHE=$(brew --cache)
HOMEBREW_REPOSITORY=$(brew --repo)
[[ -f "$HOMEBREW_CACHE/all_commands_list.txt" ]] &&
commands=($(cat "$HOMEBREW_CACHE/all_commands_list.txt")) ||
commands=($(cat "$HOMEBREW_REPOSITORY/completions/internal_commands_list.txt"))
commands=(${commands:#*instal}) # Exclude instal, uninstal, etc.
_store_cache $comp_cachename commands
if ! _retrieve_cache $comp_cachename; then
local cache_dir=$(brew --cache)
[[ -f $cache_dir/all_commands_list.txt ]] &&
list=( $(<$cache_dir/all_commands_list.txt) ) ||
list=( $(<$(brew --repo)/completions/internal_commands_list.txt) )
list=( ${list:#*instal} ) # Exclude instal, uninstal, etc.
_store_cache $comp_cachename list
fi
_describe -t all-commands 'all commands' commands
_describe -t all-commands 'all commands' list
}
__brew_commands() {
@ -857,10 +855,10 @@ _brew() {
case "$state" in
command)
# set default cache policy
zstyle -s ":completion:${curcontext%:*}:*" cache-policy tmp
[[ -n $tmp ]] ||
zstyle ":completion:${curcontext%:*}:*" cache-policy \
__brew_completion_caching_policy
zstyle -s ":completion:${curcontext%:*}:*" cache-policy tmp ||
zstyle ":completion:${curcontext%:*}:*" cache-policy __brew_completion_caching_policy
zstyle -s ":completion:${curcontext%:*}:*" use-cache tmp ||
zstyle ":completion:${curcontext%:*}:*" use-cache true
__brew_commands && return 0
;;
@ -878,10 +876,10 @@ _brew() {
# set default cache policy (we repeat this dance because the context
# service differs from above)
zstyle -s ":completion:${curcontext%:*}:*" cache-policy tmp
[[ -n $tmp ]] ||
zstyle ":completion:${curcontext%:*}:*" cache-policy \
__brew_completion_caching_policy
zstyle -s ":completion:${curcontext%:*}:*" cache-policy tmp ||
zstyle ":completion:${curcontext%:*}:*" cache-policy __brew_completion_caching_policy
zstyle -s ":completion:${curcontext%:*}:*" use-cache tmp ||
zstyle ":completion:${curcontext%:*}:*" use-cache true
# call completion for named command e.g. _brew_list
local completion_func="_brew_${command//-/_}"

View File

@ -21,7 +21,7 @@ __brew_all_casks() {
local expl
local comp_cachename=brew_casks
if _cache_invalid $comp_cachename || ! _retrieve_cache $comp_cachename; then
if ! _retrieve_cache $comp_cachename; then
list=( $(brew search --casks) )
_store_cache $comp_cachename list
fi

View File

@ -261,7 +261,7 @@ We want tests that don't require any user input and test the basic functionality
See [`cmake`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/cmake.rb) for an example of a formula with a good test. The formula writes a basic `CMakeLists.txt` file into the test directory then calls CMake to generate Makefiles. This test checks that CMake doesn't e.g. segfault during basic operation.
You can check that the output is as expected with `assert_equal` or `assert_match` on the output of shell_output such as in this example from the [envv formula](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/envv.rb):
You can check that the output is as expected with `assert_equal` or `assert_match` on the output of the [Formula assertions](https://rubydoc.brew.sh/Homebrew/Assertions.html) such as in this example from the [envv formula](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/envv.rb):
```ruby
assert_equal "mylist=A:C; export mylist", shell_output("#{bin}/envv del mylist B").strip

View File

@ -250,7 +250,7 @@ GEM
thread_safe (~> 0.1)
unicode-display_width (1.7.0)
yell (2.2.2)
zeitwerk (2.3.0)
zeitwerk (2.3.1)
PLATFORMS
ruby

View File

@ -340,6 +340,8 @@ Show install options specific to *`formula`*.
Show options for formulae that are currently installed.
* `--all`:
Show options for all available formulae.
* `--command`:
Show options for the specified *`command`*.
### `outdated` [*`options`*] [*`formula`*]

View File

@ -456,6 +456,10 @@ Show options for formulae that are currently installed\.
\fB\-\-all\fR
Show options for all available formulae\.
.
.TP
\fB\-\-command\fR
Show options for the specified \fIcommand\fR\.
.
.SS "\fBoutdated\fR [\fIoptions\fR] [\fIformula\fR]"
List installed formulae that have an updated version available\. By default, version information is displayed in interactive shells, and suppressed otherwise\.
.