Merge branch 'master' into undeclared_runtime_dependencies

This commit is contained in:
Alyssa Ross 2018-03-30 12:39:13 +01:00
commit 6bbc56c3a9
No known key found for this signature in database
GPG Key ID: 37A2D352E7A2B260
170 changed files with 2035 additions and 1057 deletions

View File

@ -32,7 +32,7 @@ onoe() {
fi
if [[ $# -eq 0 ]]
then
/bin/cat >&2
cat >&2
else
echo "$*" >&2
fi

View File

@ -44,9 +44,9 @@ class Build
def expand_reqs
formula.recursive_requirements do |dependent, req|
build = effective_build_options_for(dependent)
if (req.optional? || req.recommended?) && build.without?(req)
if req.prune_from_option?(build)
Requirement.prune
elsif req.build? && dependent != formula
elsif req.prune_if_build_and_not_dependent?(dependent, formula)
Requirement.prune
end
end
@ -55,9 +55,9 @@ class Build
def expand_deps
formula.recursive_dependencies do |dependent, dep|
build = effective_build_options_for(dependent)
if (dep.optional? || dep.recommended?) && build.without?(dep)
if dep.prune_from_option?(build)
Dependency.prune
elsif dep.build? && dependent != formula
elsif dep.prune_if_build_and_not_dependent?(dependent, formula)
Dependency.prune
elsif dep.build?
Dependency.keep_but_prune_recursive_deps

View File

@ -33,6 +33,9 @@ module Hbc
check_download
check_single_pre_postflight
check_single_uninstall_zap
check_untrusted_pkg
check_github_releases_appcast
check_latest_with_appcast
self
rescue StandardError => e
odebug "#{e.message}\n#{e.backtrace.join("\n")}"
@ -50,6 +53,18 @@ module Hbc
private
def check_untrusted_pkg
odebug "Auditing pkg stanza: allow_untrusted"
return if @cask.sourcefile_path.nil?
tap = @cask.tap
return if tap.nil? || tap.user != "caskroom"
return unless cask.artifacts.any? { |k| k.is_a?(Hbc::Artifact::Pkg) && k.stanza_options.key?(:allow_untrusted) }
add_warning "allow_untrusted is not permitted in official Homebrew-Cask taps"
end
def check_single_pre_postflight
odebug "Auditing preflight and postflight stanzas"
@ -95,7 +110,7 @@ module Hbc
def check_version_and_checksum
return if @cask.sourcefile_path.nil?
tap = Tap.select { |t| t.cask_file?(@cask.sourcefile_path) }.first
tap = @cask.tap
return if tap.nil?
return if commit_range.nil?
@ -214,6 +229,20 @@ module Hbc
end
end
def check_latest_with_appcast
return unless cask.version.latest?
return unless cask.appcast
add_warning "Casks with an appcast should not use version :latest"
end
def check_github_releases_appcast
return if cask.appcast
return unless cask.url.to_s =~ %r{github.com/([^/]+)/([^/]+)/releases/download/(\S+)}
add_warning "Cask uses GitHub releases, please add an appcast. See https://github.com/caskroom/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/appcast.md"
end
def check_url
return unless cask.url
check_download_url_format

View File

@ -97,14 +97,14 @@ module Hbc
class FromTapPathLoader < FromPathLoader
def self.can_load?(ref)
ref.to_s.match?(HOMEBREW_TAP_PATH_REGEX) && super
super && !Tap.from_path(ref).nil?
end
attr_reader :tap
def initialize(tap_path)
@tap = Tap.from_path(tap_path)
super tap_path
def initialize(path)
@tap = Tap.from_path(path)
super(path)
end
private

View File

@ -124,6 +124,7 @@ module Hbc
BUNDLE_PATH
PATH
SHELL
HOMEBREW_CASK_OPTS
]
locale_variables = ENV.keys.grep(/^(?:LC_\S+|LANG|LANGUAGE)\Z/).sort

View File

@ -154,7 +154,7 @@ module Hbc
end
def ext
Pathname.new(@url).extname[/[^?]+/]
Pathname.new(@url).extname[/[^?&]+/]
end
end

View File

@ -90,7 +90,7 @@ module Hbc
brew cask install java
EOS
elsif java_version.include?("9") || java_version.include?("+")
elsif java_version.include?("10") || java_version.include?("+")
<<~EOS
#{@cask} requires Java #{java_version}. You can install the latest version with

View File

@ -14,7 +14,7 @@ module Hbc
def initialize(signature, parameters = {})
@parameters = parameters
@signature = URI(signature)
@signature = URI(signature) unless signature == :embedded
parameters.each do |hkey, hvalue|
raise "invalid 'gpg' parameter: '#{hkey.inspect}'" unless VALID_PARAMETERS.include?(hkey)
writer_method = "#{hkey}=".to_sym

View File

@ -49,7 +49,7 @@ module Hbc
end
def verify
return unless available?
return unless available? && cask.gpg.signature != :embedded
import_key
sig = fetch_sig

View File

@ -13,6 +13,6 @@ class Checksum
delegate [:empty?, :to_s] => :@hexdigest
def ==(other)
hash_type == other.hash_type && hexdigest == other.hexdigest
hash_type == other&.hash_type && hexdigest == other.hexdigest
end
end

View File

@ -122,7 +122,7 @@ module Homebrew
lockfiles = candidates.select(&:file?)
lockfiles.each do |file|
next unless file.readable?
file.open.flock(File::LOCK_EX | File::LOCK_NB) && file.unlink
file.open(File::RDWR).flock(File::LOCK_EX | File::LOCK_NB) && file.unlink
end
end

View File

@ -0,0 +1,76 @@
require "optparse"
require "ostruct"
module Homebrew
module CLI
class Parser
def self.parse(&block)
new(&block).parse
end
def initialize(&block)
@parser = OptionParser.new
@parsed_args = OpenStruct.new
instance_eval(&block)
end
def switch(*names, description: nil, env: nil)
description = option_to_description(*names) if description.nil?
names, env = common_switch(*names) if names.first.is_a?(Symbol)
@parser.on(*names, description) do
enable_switch(*names)
end
enable_switch(*names) if !env.nil? && !ENV["HOMEBREW_#{env.to_s.upcase}"].nil?
end
def comma_array(name, description: nil)
description = option_to_description(name) if description.nil?
@parser.on(name, OptionParser::REQUIRED_ARGUMENT, Array, description) do |list|
@parsed_args[option_to_name(name)] = list
end
end
def flag(name, description: nil, required: false)
if required
option_required = OptionParser::REQUIRED_ARGUMENT
else
option_required = OptionParser::OPTIONAL_ARGUMENT
end
description = option_to_description(name) if description.nil?
@parser.on(name, description, option_required) do |option_value|
@parsed_args[option_to_name(name)] = option_value
end
end
def option_to_name(name)
name.sub(/\A--?/, "").tr("-", "_")
end
def option_to_description(*names)
names.map { |name| name.to_s.sub(/\A--?/, "").tr("-", " ") }.sort.last
end
def parse(cmdline_args = ARGV)
@parser.parse!(cmdline_args)
@parsed_args
end
private
def enable_switch(*names)
names.each do |name|
@parsed_args["#{option_to_name(name)}?"] = true
end
end
def common_switch(name)
case name
when :quiet then [["-q", "--quiet"], :quiet]
when :verbose then [["-v", "--verbose"], :verbose]
when :debug then [["-d", "--debug"], :debug]
else name
end
end
end
end
end

View File

@ -18,7 +18,7 @@
#: By default, `deps` shows required and recommended dependencies for
#: <formulae>. To include the `:build` type dependencies, pass `--include-build`.
#: Similarly, pass `--include-optional` to include `:optional` dependencies or
#: `--include-test` to include `:test` dependencies.
#: `--include-test` to include (non-recursive) `:test` dependencies.
#: To skip `:recommended` type dependencies, pass `--skip-recommended`.
#: To include requirements in addition to dependencies, pass `--include-requirements`.
#:
@ -75,30 +75,40 @@ module Homebrew
raise FormulaUnspecifiedError if ARGV.named.empty?
puts_deps_tree ARGV.formulae, !ARGV.one?
end
return
elsif mode.all?
puts_deps Formula.sort
elsif ARGV.named.empty?
return
elsif !ARGV.named.empty? && mode.for_each?
puts_deps ARGV.formulae
return
end
@only_installed_arg = ARGV.include?("--installed") &&
!ARGV.include?("--include-build") &&
!ARGV.include?("--include-test") &&
!ARGV.include?("--include-optional") &&
!ARGV.include?("--skip-recommended")
if ARGV.named.empty?
raise FormulaUnspecifiedError unless mode.installed?
puts_deps Formula.installed.sort
elsif mode.for_each?
puts_deps ARGV.formulae
else
return
end
all_deps = deps_for_formulae(ARGV.formulae, !ARGV.one?, &(mode.union? ? :| : :&))
all_deps = condense_requirements(all_deps)
all_deps = all_deps.select(&:installed?) if mode.installed?
all_deps = all_deps.map(&method(:dep_display_name)).uniq
all_deps.select!(&:installed?) if mode.installed?
all_deps.map!(&method(:dep_display_name))
all_deps.uniq!
all_deps.sort! unless mode.topo_order?
puts all_deps
end
end
def condense_requirements(deps)
if ARGV.include?("--include-requirements")
deps
else
return deps if ARGV.include?("--include-requirements")
deps.select { |dep| dep.is_a? Dependency }
end
end
def dep_display_name(dep)
str = if dep.is_a? Requirement
@ -108,70 +118,33 @@ module Homebrew
# This shouldn't happen, but we'll put something here to help debugging
"::#{dep.name}"
end
elsif ARGV.include?("--full-name")
dep.to_formula.full_name
else
ARGV.include?("--full-name") ? dep.to_formula.full_name : dep.name
dep.name
end
if ARGV.include?("--annotate")
str = "#{str} [build]" if dep.build?
str = "#{str} [test]" if dep.test?
str = "#{str} [optional" if dep.optional?
str = "#{str} [recommended]" if dep.recommended?
end
str
end
def deps_for_formula(f, recursive = false)
includes = []
ignores = []
if ARGV.include?("--include-build")
includes << "build?"
else
ignores << "build?"
end
if ARGV.include?("--include-test")
includes << "test?"
else
ignores << "test?"
end
if ARGV.include?("--include-optional")
includes << "optional?"
else
ignores << "optional?"
end
ignores << "recommended?" if ARGV.include?("--skip-recommended")
includes, ignores = argv_includes_ignores(ARGV)
deps = f.runtime_dependencies if @only_installed_arg
if recursive
deps = f.recursive_dependencies do |dependent, dep|
if dep.recommended?
Dependency.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.test?
next if includes.include?("test?")
Dependency.prune
elsif dep.optional?
Dependency.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.build?
Dependency.prune unless includes.include?("build?")
end
end
reqs = f.recursive_requirements do |dependent, req|
if req.recommended?
Requirement.prune if ignores.include?("recommended?") || dependent.build.without?(req)
elsif req.test?
next if includes.include?("test?")
Requirement.prune
elsif req.optional?
Requirement.prune if !includes.include?("optional?") && !dependent.build.with?(req)
elsif req.build?
Requirement.prune unless includes.include?("build?")
end
end
deps ||= recursive_includes(Dependency, f, includes, ignores)
reqs = recursive_includes(Requirement, f, includes, ignores)
else
deps = f.deps.reject do |dep|
ignores.any? { |ignore| dep.send(ignore) } && includes.none? { |include| dep.send(include) }
end
reqs = f.requirements.reject do |req|
ignores.any? { |ignore| req.send(ignore) } && includes.none? { |include| req.send(include) }
end
deps ||= reject_ignores(f.deps, ignores, includes)
reqs = reject_ignores(f.requirements, ignores, includes)
end
deps + reqs.to_a
@ -185,7 +158,8 @@ module Homebrew
formulae.each do |f|
deps = deps_for_formula(f)
deps = condense_requirements(deps)
deps = deps.sort_by(&:name).map(&method(:dep_display_name))
deps.sort_by!(&:name)
deps.map!(&method(:dep_display_name))
puts "#{f.full_name}: #{deps.join(" ")}"
end
end
@ -203,33 +177,39 @@ module Homebrew
reqs = f.requirements
deps = f.deps
dependables = reqs + deps
dependables = dependables.reject(&:optional?) unless ARGV.include?("--include-optional")
dependables = dependables.reject(&:build?) unless ARGV.include?("--include-build")
dependables = dependables.reject(&:test?) unless ARGV.include?("--include-test")
dependables = dependables.reject(&:recommended?) if ARGV.include?("--skip-recommended")
dependables.reject!(&:optional?) unless ARGV.include?("--include-optional")
dependables.reject!(&:build?) unless ARGV.include?("--include-build")
dependables.reject!(&:test?) unless ARGV.include?("--include-test")
dependables.reject!(&:recommended?) if ARGV.include?("--skip-recommended")
max = dependables.length - 1
@dep_stack.push f.name
dependables.each_with_index do |dep, i|
next if !ARGV.include?("--include-requirements") && dep.is_a?(Requirement)
tree_lines = if i == max
"└──"
else
"├──"
end
display_s = "#{tree_lines} #{dep_display_name(dep)}"
is_circular = @dep_stack.include?(dep.name)
display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular
puts "#{prefix}#{display_s}"
next if !recursive || is_circular
prefix_addition = if i == max
" "
else
""
end
if dep.is_a? Dependency
recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_addition, true)
end
end
@dep_stack.pop
end
end

View File

@ -74,14 +74,13 @@ module Homebrew
end
def command_help(path)
help_lines = path.read.lines.grep(/^#:/)
help_lines = command_help_lines(path)
if help_lines.empty?
opoo "No help text in: #{path}" if ARGV.homebrew_developer?
HOMEBREW_HELP
else
help_lines.map do |line|
line.slice(2..-1)
.sub(/^ \* /, "#{Tty.bold}brew#{Tty.reset} ")
line.sub(/^ \* /, "#{Tty.bold}brew#{Tty.reset} ")
.gsub(/`(.*?)`/, "#{Tty.bold}\\1#{Tty.reset}")
.gsub(%r{<([^\s]+?://[^\s]+?)>}) { |url| Formatter.url(url) }
.gsub(/<(.*?)>/, "#{Tty.underline}\\1#{Tty.reset}")

View File

@ -1,4 +1,4 @@
#: * `install` [`--debug`] [`--env=`(`std`|`super`)] [`--ignore-dependencies`|`--only-dependencies`] [`--cc=`<compiler>] [`--build-from-source`|`--force-bottle`] [`--devel`|`--HEAD`] [`--keep-tmp`] [`--build-bottle`] [`--force`] [`--verbose`] <formula> [<options> ...]:
#: * `install` [`--debug`] [`--env=`(`std`|`super`)] [`--ignore-dependencies`|`--only-dependencies`] [`--cc=`<compiler>] [`--build-from-source`|`--force-bottle`] [`--include-test`] [`--devel`|`--HEAD`] [`--keep-tmp`] [`--build-bottle`] [`--force`] [`--verbose`] <formula> [<options> ...]:
#: Install <formula>.
#:
#: <formula> is usually the name of the formula to install, but it can be specified
@ -36,6 +36,9 @@
#: current or newest version of macOS, even if it would not normally be used
#: for installation.
#:
#: If `--include-test` is passed, install testing dependencies. These are only
#: needed by formulae maintainers to run `brew test`.
#:
#: If `--devel` is passed, and <formula> defines it, install the development version.
#:
#: If `--HEAD` is passed, and <formula> defines it, install the HEAD version,
@ -159,6 +162,8 @@ module Homebrew
#{f.full_name} #{optlinked_version} is already installed
To upgrade to #{f.version}, run `brew upgrade #{f.name}`
EOS
elsif ARGV.only_deps?
formulae << f
else
opoo <<~EOS
#{f.full_name} #{f.pkg_version} is already installed
@ -188,8 +193,11 @@ module Homebrew
#{msg}, it's just not linked.
You can use `brew link #{f}` to link this version.
EOS
elsif ARGV.only_deps?
msg = nil
formulae << f
end
opoo msg
opoo msg if msg
elsif !f.any_version_installed? && old_formula = f.old_installed_formulae.first
msg = "#{old_formula.full_name} #{old_formula.installed_version} already installed"
if !old_formula.linked? && !old_formula.keg_only?
@ -249,10 +257,10 @@ module Homebrew
return
end
query = query_regexp(e.name)
regex = query_regexp(e.name)
ohai "Searching for similarly named formulae..."
formulae_search_results = search_formulae(query)
formulae_search_results = search_formulae(regex)
case formulae_search_results.length
when 0
ofail "No similarly named formulae found."
@ -269,7 +277,7 @@ module Homebrew
# Do not search taps if the formula name is qualified
return if e.name.include?("/")
ohai "Searching taps..."
taps_search_results = search_taps(query)
taps_search_results = search_taps(e.name)
case taps_search_results.length
when 0
ofail "No formulae found in taps."

View File

@ -10,15 +10,18 @@ module Homebrew
def leaves
installed = Formula.installed.sort
deps_of_installed = Set.new
installed.each do |f|
deps = f.runtime_dependencies.map { |d| d.to_formula.full_name }
deps_of_installed.merge(deps)
deps_of_installed = installed.flat_map do |f|
f.runtime_dependencies.map do |dep|
begin
dep.to_formula.full_name
rescue FormulaUnavailableError
dep.name
end
end
end
installed.each do |f|
puts f.full_name unless deps_of_installed.include? f.full_name
end
leaves = installed.map(&:full_name) - deps_of_installed
leaves.each(&method(:puts))
end
end

View File

@ -11,6 +11,8 @@
#: If `--display-cop-names` is passed, include the RuboCop cop name for each
#: violation in the output.
#:
#: If `--rspec` is passed, install and use the RuboCop RSpec gem.
#:
#: Passing `--only-cops=`<cops> will check for violations of only the listed
#: RuboCop <cops>, while `--except-cops=`<cops> will skip checking the listed
#: <cops>. For either option <cops> should be a comma-separated list of cop names.
@ -83,6 +85,11 @@ module Homebrew
args << "--parallel"
end
if ARGV.include?("--rspec")
Homebrew.install_gem! "rubocop-rspec"
args += %w[--require rubocop-rspec]
end
if options[:except_cops]
options[:except_cops].map! { |cop| RuboCop::Cop::Cop.registry.qualified_cop_name(cop.to_s, "") }
cops_to_exclude = options[:except_cops].select do |cop|

View File

@ -23,15 +23,8 @@ git() {
}
git_init_if_necessary() {
if [[ -n "$HOMEBREW_MACOS" ]] || [[ -n "$HOMEBREW_FORCE_HOMEBREW_ORG" ]]
then
BREW_OFFICIAL_REMOTE="https://github.com/Homebrew/brew"
CORE_OFFICIAL_REMOTE="https://github.com/Homebrew/homebrew-core"
elif [[ -n "$HOMEBREW_LINUX" ]]
then
BREW_OFFICIAL_REMOTE="https://github.com/Linuxbrew/brew"
CORE_OFFICIAL_REMOTE="https://github.com/Linuxbrew/homebrew-core"
fi
safe_cd "$HOMEBREW_REPOSITORY"
if [[ ! -d ".git" ]]

View File

@ -1,15 +1,19 @@
#: * `upgrade` [<install-options>] [`--cleanup`] [`--fetch-HEAD`] [<formulae>]:
#: * `upgrade` [<install-options>] [`--cleanup`] [`--fetch-HEAD`] [`--ignore-pinned`] [<formulae>]:
#: Upgrade outdated, unpinned brews (with existing install options).
#:
#: Options for the `install` command are also valid here.
#:
#: If `--cleanup` is specified then remove previously installed <formula> version(s).
#: If `--cleanup` is specified or `HOMEBREW_UPGRADE_CLEANUP` is set then remove
#: previously installed <formula> version(s).
#:
#: If `--fetch-HEAD` is passed, fetch the upstream repository to detect if
#: the HEAD installation of the formula is outdated. Otherwise, the
#: repository's HEAD will be checked for updates when a new stable or devel
#: version has been released.
#:
#: If `--ignore-pinned` is passed, set a 0 exit code even if pinned formulae
#: are not upgraded.
#:
#: If <formulae> are given, upgrade only the specified brews (unless they
#: are pinned; see `pin`, `unpin`).
@ -54,6 +58,11 @@ module Homebrew
outdated -= pinned
formulae_to_install = outdated.map(&:latest_formula)
if !pinned.empty? && !ARGV.include?("--ignore-pinned")
ofail "Not upgrading #{Formatter.pluralize(pinned.length, "pinned package")}:"
puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
end
if formulae_to_install.empty?
oh1 "No packages to upgrade"
else
@ -61,11 +70,6 @@ module Homebrew
puts formulae_to_install.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
end
unless pinned.empty?
onoe "Not upgrading #{Formatter.pluralize(pinned.length, "pinned package")}:"
puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
end
# Sort keg_only before non-keg_only formulae to avoid any needless conflicts
# with outdated, non-keg_only versions of formulae being upgraded.
formulae_to_install.sort! do |a, b|
@ -82,7 +86,7 @@ module Homebrew
Migrator.migrate_if_needed(f)
begin
upgrade_formula(f)
next unless ARGV.include?("--cleanup")
next if !ARGV.include?("--cleanup") && !ENV["HOMEBREW_UPGRADE_CLEANUP"]
next unless f.installed?
Homebrew::Cleanup.cleanup_formula f
rescue UnsatisfiedRequirements => e

View File

@ -1,4 +1,4 @@
#: * `uses` [`--installed`] [`--recursive`] [`--include-build`] [`--include-optional`] [`--skip-recommended`] [`--devel`|`--HEAD`] <formulae>:
#: * `uses` [`--installed`] [`--recursive`] [`--include-build`] [`--include-test`] [`--include-optional`] [`--skip-recommended`] [`--devel`|`--HEAD`] <formulae>:
#: Show the formulae that specify <formulae> as a dependency. When given
#: multiple formula arguments, show the intersection of formulae that use
#: <formulae>.
@ -9,10 +9,12 @@
#:
#: By default, `uses` shows all formulae that specify <formulae> as a required
#: or recommended dependency. To include the `:build` type dependencies, pass
#: `--include-build`. Similarly, pass `--include-optional` to include `:optional`
#: dependencies. To skip `:recommended` type dependencies, pass `--skip-recommended`.
#: `--include-build`, to include the `:test` type dependencies, pass
#: `--include-test` and to include `:optional` dependencies pass
#: `--include-optional`. To skip `:recommended` type dependencies, pass
#: `--skip-recommended`.
#:
#: By default, `uses` shows usages of <formulae> by stable builds. To find
#: By default, `uses` shows usage of <formulae> by stable builds. To find
#: cases where <formulae> is used by development or HEAD build, pass
#: `--devel` or `--HEAD`.
@ -40,39 +42,20 @@ module Homebrew
formulae = ARGV.include?("--installed") ? Formula.installed : Formula
recursive = ARGV.flag? "--recursive"
includes = []
ignores = []
if ARGV.include? "--include-build"
includes << "build?"
else
ignores << "build?"
end
if ARGV.include? "--include-optional"
includes << "optional?"
else
ignores << "optional?"
end
ignores << "recommended?" if ARGV.include? "--skip-recommended"
only_installed_arg = ARGV.include?("--installed") &&
!ARGV.include?("--include-build") &&
!ARGV.include?("--include-test") &&
!ARGV.include?("--include-optional") &&
!ARGV.include?("--skip-recommended")
includes, ignores = argv_includes_ignores(ARGV)
uses = formulae.select do |f|
used_formulae.all? do |ff|
begin
deps = f.runtime_dependencies if only_installed_arg
if recursive
deps = f.recursive_dependencies do |dependent, dep|
if dep.recommended?
Dependency.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.optional?
Dependency.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.build?
Dependency.prune unless includes.include?("build?")
end
# If a tap isn't installed, we can't find the dependencies of one
# its formulae, and an exception will be thrown if we try.
if dep.is_a?(TapDependency) && !dep.tap.installed?
Dependency.keep_but_prune_recursive_deps
end
end
deps ||= recursive_includes(Dependency, f, includes, ignores)
dep_formulae = deps.flat_map do |dep|
begin
@ -89,6 +72,8 @@ module Homebrew
reqs_by_formula.reject! do |dependent, req|
if req.recommended?
ignores.include?("recommended?") || dependent.build.without?(req)
elsif req.test?
!includes.include?("test?")
elsif req.optional?
!includes.include?("optional?") && !dependent.build.with?(req)
elsif req.build?
@ -98,13 +83,10 @@ module Homebrew
reqs = reqs_by_formula.map(&:last)
else
deps = f.deps.reject do |dep|
ignores.any? { |ignore| dep.send(ignore) } && includes.none? { |include| dep.send(include) }
end
reqs = f.requirements.reject do |req|
ignores.any? { |ignore| req.send(ignore) } && includes.none? { |include| req.send(include) }
end
deps ||= reject_ignores(f.deps, ignores, includes)
reqs = reject_ignores(f.requirements, ignores, includes)
end
next true if deps.any? do |dep|
begin
dep.to_formula.full_name == ff.full_name

View File

@ -114,10 +114,10 @@ EOS
if [[ -x "/usr/bin/shasum" ]]
then
sha="$(/usr/bin/shasum -a 256 "$CACHED_LOCATION" | cut -d' ' -f1)"
elif [[ -x "$(which sha256sum)" ]]
elif [[ -x "$(type -P sha256sum)" ]]
then
sha="$(sha256sum "$CACHED_LOCATION" | cut -d' ' -f1)"
elif [[ -x "$(which ruby)" ]]
elif [[ -x "$(type -P ruby)" ]]
then
sha="$(ruby <<EOSCRIPT
require 'digest/sha2'

View File

@ -29,3 +29,4 @@ require "compat/ENV/super"
require "compat/utils/shell"
require "compat/extend/string"
require "compat/gpg"
require "compat/dependable"

View File

@ -0,0 +1,5 @@
module Dependable
def run?
tags.include? :run
end
end

View File

@ -33,7 +33,6 @@ class DependencyCollector
output_deprecation(spec)
Dependency.new(spec.to_s, tags)
when :libltdl
tags << :run
output_deprecation("libtool")
Dependency.new("libtool", tags)
when :apr
@ -68,7 +67,7 @@ class DependencyCollector
private
def autotools_dep(spec, tags)
tags << :build unless tags.include? :run
tags << :build
Dependency.new(spec.to_s, tags)
end

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true
# RuboCop version used for `brew style` and `brew cask style`
HOMEBREW_RUBOCOP_VERSION = "0.53.0"
HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.17.0" # has to be updated when RuboCop version changes
HOMEBREW_RUBOCOP_VERSION = "0.54.0"
HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.18.0" # has to be updated when RuboCop version changes

View File

@ -1,6 +1,8 @@
require "options"
module Dependable
# :run and :linked are no longer used but keep them here to avoid them being
# misused in future.
RESERVED_TAGS = [:build, :optional, :recommended, :run, :test, :linked].freeze
def build?
@ -15,10 +17,6 @@ module Dependable
tags.include? :recommended
end
def run?
tags.include? :run
end
def test?
tags.include? :test
end
@ -34,4 +32,15 @@ module Dependable
def options
Options.create(option_tags)
end
def prune_from_option?(build)
return if !optional? && !recommended?
build.without?(self)
end
def prune_if_build_and_not_dependent?(dependent, formula = nil)
return false unless build?
return dependent.installed? unless formula
dependent != formula
end
end

View File

@ -52,3 +52,81 @@ class Requirements < DelegateClass(Set)
"#<#{self.class.name}: {#{to_a.join(", ")}}>"
end
end
module Homebrew
module_function
def argv_includes_ignores(argv)
includes = []
ignores = []
if argv.include? "--include-build"
includes << "build?"
else
ignores << "build?"
end
if argv.include? "--include-test"
includes << "test?"
else
ignores << "test?"
end
if argv.include? "--include-optional"
includes << "optional?"
else
ignores << "optional?"
end
ignores << "recommended?" if ARGV.include? "--skip-recommended"
[includes, ignores]
end
def recursive_includes(klass, formula, includes, ignores)
type = if klass == Dependency
:dependencies
elsif klass == Requirement
:requirements
else
raise ArgumentError, "Invalid class argument: #{klass}"
end
formula.send("recursive_#{type}") do |dependent, dep|
if dep.recommended?
if ignores.include?("recommended?") || dependent.build.without?(dep)
klass.prune
end
elsif dep.test?
if includes.include?("test?")
if type == :dependencies
Dependency.keep_but_prune_recursive_deps
end
else
klass.prune
end
elsif dep.optional?
if !includes.include?("optional?") && !dependent.build.with?(dep)
klass.prune
end
elsif dep.build?
klass.prune unless includes.include?("build?")
end
# If a tap isn't installed, we can't find the dependencies of one
# its formulae, and an exception will be thrown if we try.
if type == :dependencies &&
dep.is_a?(TapDependency) &&
!dep.tap.installed?
Dependency.keep_but_prune_recursive_deps
end
end
end
def reject_ignores(dependables, ignores, includes)
dependables.reject do |dep|
next false unless ignores.any? { |ignore| dep.send(ignore) }
includes.none? { |include| dep.send(include) }
end
end
end

View File

@ -83,6 +83,9 @@ class Dependency
deps.each do |dep|
next if dependent.name == dep.name
# we only care about one level of test dependencies.
next if dep.test? && @expand_stack.length > 1
case action(dependent, dep, &block)
when :prune
next
@ -160,13 +163,9 @@ class Dependency
end
def merge_temporality(deps)
if deps.all?(&:build?)
# Means both build and runtime dependency.
return [] unless deps.all?(&:build?)
[:build]
elsif deps.all?(&:run?)
[:run]
else
[] # Means both build and runtime dependency.
end
end
end
end

View File

@ -49,20 +49,36 @@ require "cmd/style"
require "date"
require "missing_formula"
require "digest"
require "cli_parser"
module Homebrew
module_function
def audit
inject_dump_stats!(FormulaAuditor, /^audit_/) if ARGV.switch? "D"
args = Homebrew::CLI::Parser.parse do
switch "--strict"
switch "--online"
switch "--new-formula"
switch "--fix"
switch "--display-cop-names"
switch "--display-filename"
switch "-D", "--audit-debug", description: "Activates debugging and profiling"
switch :verbose
switch :debug
comma_array "--only"
comma_array "--except"
comma_array "--only-cops"
comma_array "--except-cops"
end
Homebrew.auditing = true
inject_dump_stats!(FormulaAuditor, /^audit_/) if args.audit_debug?
formula_count = 0
problem_count = 0
new_formula = ARGV.include? "--new-formula"
strict = new_formula || ARGV.include?("--strict")
online = new_formula || ARGV.include?("--online")
new_formula = args.new_formula?
strict = new_formula || args.strict?
online = new_formula || args.online?
ENV.activate_extensions!
ENV.setup_build_environment
@ -75,35 +91,36 @@ module Homebrew
files = ARGV.resolved_formulae.map(&:path)
end
only_cops = ARGV.value("only-cops").to_s.split(",")
except_cops = ARGV.value("except-cops").to_s.split(",")
only_cops = args.only_cops
except_cops = args.except_cops
if !only_cops.empty? && !except_cops.empty?
if only_cops && except_cops
odie "--only-cops and --except-cops cannot be used simultaneously!"
elsif (!only_cops.empty? || !except_cops.empty?) && (strict || ARGV.value("only"))
elsif (only_cops || except_cops) && (strict || args.only)
odie "--only-cops/--except-cops and --strict/--only cannot be used simultaneously"
end
options = { fix: ARGV.flag?("--fix"), realpath: true }
options = { fix: args.fix?, realpath: true }
if !only_cops.empty?
if only_cops
options[:only_cops] = only_cops
ARGV.push("--only=style")
elsif new_formula
args.only = ["style"]
elsif args.new_formula?
nil
elsif strict
options[:except_cops] = [:NewFormulaAudit]
elsif !except_cops.empty?
elsif except_cops
options[:except_cops] = except_cops
elsif !strict
options[:only_cops] = [:FormulaAudit]
end
options[:display_cop_names] = args.display_cop_names?
# Check style in a single batch run up front for performance
style_results = check_style_json(files, options)
ff.sort.each do |f|
options = { new_formula: new_formula, strict: strict, online: online }
options = { new_formula: new_formula, strict: strict, online: online, only: args.only, except: args.except }
options[:style_offenses] = style_results.file_offenses(f.path)
fa = FormulaAuditor.new(f, options)
fa.audit
@ -113,7 +130,7 @@ module Homebrew
formula_count += 1
problem_count += fa.problems.size
problem_lines = fa.problems.map { |p| "* #{p.chomp.gsub("\n", "\n ")}" }
if ARGV.include? "--display-filename"
if args.display_filename?
puts problem_lines.map { |s| "#{f.path}: #{s}" }
else
puts "#{f.full_name}:", problem_lines.map { |s| " #{s}" }
@ -172,28 +189,14 @@ class FormulaAuditor
attr_reader :formula, :text, :problems
BUILD_TIME_DEPS = %w[
autoconf
automake
boost-build
bsdmake
cmake
godep
imake
intltool
libtool
pkg-config
scons
smake
sphinx-doc
swig
].freeze
def initialize(formula, options = {})
@formula = formula
@new_formula = options[:new_formula]
@strict = options[:strict]
@online = options[:online]
@display_cop_names = options[:display_cop_names]
@only = options[:only]
@except = options[:except]
# Accept precomputed style offense results, for efficiency
@style_offenses = options[:style_offenses]
# Allow the actual official-ness of a formula to be overridden, for testing purposes
@ -205,9 +208,8 @@ class FormulaAuditor
def audit_style
return unless @style_offenses
display_cop_names = ARGV.include?("--display-cop-names")
@style_offenses.each do |offense|
problem offense.to_s(display_cop_name: display_cop_names)
problem offense.to_s(display_cop_name: @display_cop_names)
end
end
@ -377,17 +379,12 @@ class FormulaAuditor
problem "Dependency #{dep} does not define option #{opt.name.inspect}"
end
case dep.name
when "git"
if dep.name == "git"
problem "Don't use git as a dependency (it's always available)"
when *BUILD_TIME_DEPS
next if dep.build? || dep.run?
problem <<~EOS
#{dep} dependency should be
depends_on "#{dep}" => :build
Or if it is indeed a runtime dependency
depends_on "#{dep}" => :run
EOS
end
if dep.tags.include?(:run)
problem "Dependency '#{dep.name}' is marked as :run. Remove :run; it is a no-op."
end
end
end
@ -569,6 +566,7 @@ class FormulaAuditor
gtk-doc 1.25
libart 2.3.21
pygtkglext 1.1.0
libepoxy 1.5.0
].each_slice(2).to_a.map do |formula, version|
[formula, version.split(".")[0..1].join(".")]
end
@ -789,17 +787,17 @@ class FormulaAuditor
end
def audit
only_audits = ARGV.value("only").to_s.split(",")
except_audits = ARGV.value("except").to_s.split(",")
if !only_audits.empty? && !except_audits.empty?
only_audits = @only
except_audits = @except
if only_audits && except_audits
odie "--only and --except cannot be used simultaneously!"
end
methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name|
name = audit_method_name.gsub(/^audit_/, "")
if !only_audits.empty?
if only_audits
next unless only_audits.include?(name)
elsif !except_audits.empty?
elsif except_audits
next if except_audits.include?(name)
end
send(audit_method_name)
@ -949,13 +947,13 @@ class ResourceAuditor
problem http_content_problem
end
elsif strategy <= GitDownloadStrategy
unless Utils.git_remote_exists url
unless Utils.git_remote_exists? url
problem "The URL #{url} is not a valid git URL"
end
elsif strategy <= SubversionDownloadStrategy
next unless DevelopmentTools.subversion_handles_most_https_certificates?
next unless Utils.svn_available?
unless Utils.svn_remote_exists url
unless Utils.svn_remote_exists? url
problem "The URL #{url} is not a valid svn URL"
end
end

View File

@ -34,6 +34,7 @@ require "utils/bottles"
require "tab"
require "keg"
require "formula_versions"
require "cli_parser"
require "utils/inreplace"
require "erb"
require "extend/pathname"
@ -68,6 +69,26 @@ MAXIMUM_STRING_MATCHES = 100
module Homebrew
module_function
def bottle
@args = Homebrew::CLI::Parser.parse do
switch "--merge"
switch "--skip-relocation"
switch "--force-core-tap"
switch "--no-rebuild"
switch "--keep-old"
switch "--write"
switch "--no-commit"
switch "--json"
switch :verbose
flag "--root-url"
end
return merge if @args.merge?
ARGV.resolved_formulae.each do |f|
bottle_formula f
end
end
def keg_contain?(string, keg, ignores)
@put_string_exists_header, @put_filenames = nil
@ -93,7 +114,7 @@ module Homebrew
linked_libraries = Keg.file_linked_libraries(file, string)
result ||= !linked_libraries.empty?
if ARGV.verbose?
if @args.verbose?
print_filename.call(string, file) unless linked_libraries.empty?
linked_libraries.each do |lib|
puts " #{Tty.bold}-->#{Tty.reset} links to #{lib}"
@ -116,7 +137,7 @@ module Homebrew
end
end
next unless ARGV.verbose? && !text_matches.empty?
next unless @args.verbose? && !text_matches.empty?
print_filename.call(string, file)
text_matches.first(MAXIMUM_STRING_MATCHES).each do |match, offset|
puts " #{Tty.bold}-->#{Tty.reset} match '#{match}' at offset #{Tty.bold}0x#{offset}#{Tty.reset}"
@ -137,7 +158,7 @@ module Homebrew
absolute_symlinks_start_with_string << pn if link.to_s.start_with?(string)
end
if ARGV.verbose?
if @args.verbose?
unless absolute_symlinks_start_with_string.empty?
opoo "Absolute symlink starting with #{string}:"
absolute_symlinks_start_with_string.each do |pn|
@ -160,7 +181,7 @@ module Homebrew
end
unless tap = f.tap
unless ARGV.include?("--force-core-tap")
unless @args.force_core_tap?
return ofail "Formula not from core or any taps: #{f.full_name}"
end
@ -179,9 +200,9 @@ module Homebrew
return ofail "Formula has no stable version: #{f.full_name}" unless f.stable
if ARGV.include?("--no-rebuild") || !f.tap
if @args.no_rebuild? || !f.tap
rebuild = 0
elsif ARGV.include? "--keep-old"
elsif @args.keep_old?
rebuild = f.bottle_specification.rebuild
else
ohai "Determining #{f.full_name} bottle rebuild..."
@ -214,7 +235,7 @@ module Homebrew
begin
keg.delete_pyc_files!
unless ARGV.include? "--skip-relocation"
unless @args.skip_relocation?
changed_files = keg.replace_locations_with_placeholders
end
@ -265,7 +286,7 @@ module Homebrew
end
relocatable = true
if ARGV.include? "--skip-relocation"
if @args.skip_relocation?
skip_relocation = true
else
relocatable = false if keg_contain?(prefix_check, keg, ignores)
@ -278,23 +299,21 @@ module Homebrew
end
skip_relocation = relocatable && !keg.require_relocation?
end
puts if !relocatable && ARGV.verbose?
puts if !relocatable && @args.verbose?
rescue Interrupt
ignore_interrupts { bottle_path.unlink if bottle_path.exist? }
raise
ensure
ignore_interrupts do
original_tab&.write
unless ARGV.include? "--skip-relocation"
unless @args.skip_relocation?
keg.replace_placeholders_with_locations changed_files
end
end
end
end
root_url = ARGV.value("root-url")
# Use underscored version for legacy reasons. Remove at some point.
root_url ||= ARGV.value("root_url")
root_url = @args.root_url
bottle = BottleSpecification.new
bottle.tap = tap
@ -314,7 +333,7 @@ module Homebrew
bottle.sha256 sha256 => Utils::Bottles.tag
old_spec = f.bottle_specification
if ARGV.include?("--keep-old") && !old_spec.checksums.empty?
if @args.keep_old? && !old_spec.checksums.empty?
mismatches = [:root_url, :prefix, :cellar, :rebuild].reject do |key|
old_spec.send(key) == bottle.send(key)
end
@ -340,7 +359,7 @@ module Homebrew
puts "./#{filename}"
puts output
return unless ARGV.include? "--json"
return unless @args.json?
json = {
f.full_name => {
"formula" => {
@ -371,7 +390,7 @@ module Homebrew
end
def merge
write = ARGV.include? "--write"
write = @args.write?
bottles_hash = ARGV.named.reduce({}) do |hash, json_file|
deep_merge_hashes hash, JSON.parse(IO.read(json_file))
@ -400,7 +419,7 @@ module Homebrew
Utils::Inreplace.inreplace(path) do |s|
if s.include? "bottle do"
update_or_add = "update"
if ARGV.include? "--keep-old"
if @args.keep_old?
mismatches = []
bottle_block_contents = s[/ bottle do(.+?)end\n/m, 1]
bottle_block_contents.lines.each do |line|
@ -443,7 +462,7 @@ module Homebrew
string = s.sub!(/ bottle do.+?end\n/m, output)
odie "Bottle block update failed!" unless string
else
if ARGV.include? "--keep-old"
if @args.keep_old?
odie "--keep-old was passed but there was no existing bottle block!"
end
puts output
@ -472,7 +491,7 @@ module Homebrew
end
end
unless ARGV.include? "--no-commit"
unless @args.no_commit?
if ENV["HOMEBREW_GIT_NAME"]
ENV["GIT_AUTHOR_NAME"] =
ENV["GIT_COMMITTER_NAME"] =
@ -498,14 +517,4 @@ module Homebrew
end
end
end
def bottle
if ARGV.include? "--merge"
merge
else
ARGV.resolved_formulae.each do |f|
bottle_formula f
end
end
end
end

View File

@ -190,6 +190,7 @@ class FormulaCreator
<% elsif mode.nil? %>
# depends_on "cmake" => :build
<% end %>
def install
# ENV.deparallelize # if your formula fails when building in parallel
<% if mode == :cmake %>
@ -219,6 +220,7 @@ class FormulaCreator
system "make", "install" # if this fails, try separate make/make install steps
<% end %>
end
test do
# `test do` will create, run in and delete a temporary directory.
#

View File

@ -5,11 +5,16 @@
#: Open <formula> in the editor.
require "formula"
require "cli_parser"
module Homebrew
module_function
def edit
args = Homebrew::CLI::Parser.parse do
switch "--force"
end
unless (HOMEBREW_REPOSITORY/".git").directory?
raise <<~EOS
Changes will be lost!
@ -36,7 +41,7 @@ module Homebrew
paths = ARGV.named.map do |name|
path = Formulary.path(name)
raise FormulaUnavailableError, name unless path.file? || ARGV.force?
raise FormulaUnavailableError, name unless path.file? || args.force?
path
end

View File

@ -5,6 +5,8 @@
#: If `--pry` is passed or HOMEBREW_PRY is set, pry will be
#: used instead of irb.
require "cli_parser"
class Symbol
def f(*args)
Formulary.factory(to_s, *args)
@ -21,7 +23,12 @@ module Homebrew
module_function
def irb
if ARGV.include? "--examples"
args = Homebrew::CLI::Parser.parse do
switch "--examples"
switch "--pry", env: :pry
end
if args.examples?
puts "'v8'.f # => instance of the v8 formula"
puts ":hub.f.installed?"
puts ":lua.f.methods - 1.methods"
@ -29,7 +36,7 @@ module Homebrew
return
end
if ARGV.pry?
if args.pry?
Homebrew.install_gem_setup_path! "pry"
require "pry"
Pry.config.prompt_name = "brew"
@ -45,7 +52,7 @@ module Homebrew
ohai "Interactive Homebrew Shell"
puts "Example commands available with: brew irb --examples"
if ARGV.pry?
if args.pry?
Pry.start
else
IRB.start

View File

@ -10,6 +10,7 @@
require "formula"
require "erb"
require "ostruct"
require "cli_parser"
module Homebrew
module_function
@ -19,9 +20,14 @@ module Homebrew
TARGET_DOC_PATH = HOMEBREW_REPOSITORY/"docs"
def man
@args = Homebrew::CLI::Parser.parse do
switch "--fail-if-changed"
switch "--link"
end
raise UsageError unless ARGV.named.empty?
if ARGV.flag? "--link"
if @args.link?
odie "`brew man --link` is now done automatically by `brew update`."
end
@ -29,7 +35,7 @@ module Homebrew
if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/Manpage.md", "manpages"
puts "No changes to manpage output detected."
elsif ARGV.include?("--fail-if-changed")
elsif @args.fail_if_changed?
Homebrew.failed = true
end
end
@ -71,6 +77,9 @@ module Homebrew
variables[:former_maintainers] = readme.read[/(Former maintainers .*\.)/, 1]
.gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
variables[:homebrew_bundle] = help_output(:bundle)
variables[:homebrew_services] = help_output(:services)
ERB.new(template, nil, ">").result(variables.instance_eval { binding })
end
@ -85,7 +94,7 @@ module Homebrew
# Set the manpage date to the existing one if we're checking for changes.
# This avoids the only change being e.g. a new date.
date = if ARGV.include?("--fail-if-changed") &&
date = if @args.fail_if_changed? &&
target.extname == ".1" && target.exist?
/"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read
Date.parse("#{Regexp.last_match(1)} #{Regexp.last_match(2)} #{Regexp.last_match(3)}")
@ -113,6 +122,12 @@ module Homebrew
end
end
def help_output(command)
tap = Tap.fetch("Homebrew/homebrew-#{command}")
tap.install unless tap.installed?
command_help_lines(which("brew-#{command}.rb", Tap.cmd_directories))
end
def target_path_to_format(target)
case target.basename
when /\.md$/ then ["--markdown", "markdown"]

View File

@ -52,6 +52,7 @@ require "net/http"
require "net/https"
require "utils"
require "json"
require "cli_parser"
require "formula"
require "formulary"
require "tap"
@ -62,8 +63,7 @@ module GitHub
module_function
# Return the corresponding test-bot user name for the given GitHub organization.
def test_bot_user(user)
test_bot = ARGV.value "test-bot-user"
def test_bot_user(user, test_bot)
return test_bot if test_bot
return "BrewTestBot" if user.casecmp("homebrew").zero?
"#{user.capitalize}TestBot"
@ -76,6 +76,20 @@ module Homebrew
def pull
odie "You meant `git pull --rebase`." if ARGV[0] == "--rebase"
@args = Homebrew::CLI::Parser.parse do
switch "--bottle"
switch "--bump"
switch "--clean"
switch "--ignore-whitespace"
switch "--resolve"
switch "--branch-okay"
switch "--no-pbcopy"
switch "--no-publish"
switch "--warn-on-publish-failure"
flag "--bintray-org", required: true
flag "--test-bot-user", required: true
end
if ARGV.named.empty?
odie "This command requires at least one argument containing a URL or pull request number"
end
@ -88,7 +102,7 @@ module Homebrew
ENV["GIT_COMMITTER_EMAIL"] = ENV["HOMEBREW_GIT_EMAIL"]
end
do_bump = ARGV.include?("--bump") && !ARGV.include?("--clean")
do_bump = @args.bump? && !@args.clean?
# Formulae with affected bottles that were published
bintray_published_formulae = []
@ -107,7 +121,7 @@ module Homebrew
end
_, testing_job = *testing_match
url = "https://github.com/Homebrew/homebrew-#{tap.repo}/compare/master...BrewTestBot:testing-#{testing_job}"
odie "Testing URLs require `--bottle`!" unless ARGV.include?("--bottle")
odie "Testing URLs require `--bottle`!" unless @args.bottle?
elsif (api_match = arg.match HOMEBREW_PULL_API_REGEX)
_, user, repo, issue = *api_match
url = "https://github.com/#{user}/#{repo}/pull/#{issue}"
@ -119,7 +133,7 @@ module Homebrew
odie "Not a GitHub pull request or commit: #{arg}"
end
if !testing_job && ARGV.include?("--bottle") && issue.nil?
if !testing_job && @args.bottle? && issue.nil?
odie "No pull request detected!"
end
@ -137,11 +151,11 @@ module Homebrew
orig_revision = `git rev-parse --short HEAD`.strip
branch = `git symbolic-ref --short HEAD`.strip
unless branch == "master" || ARGV.include?("--clean") || ARGV.include?("--branch-okay")
unless branch == "master" || @args.clean? || @args.branch_okay?
opoo "Current branch is #{branch}: do you need to pull inside master?"
end
patch_puller = PatchPuller.new(url)
patch_puller = PatchPuller.new(url, @args)
patch_puller.fetch_patch
patch_changes = files_changed_in_patch(patch_puller.patchpath, tap)
@ -189,7 +203,7 @@ module Homebrew
end
end
if ARGV.include? "--bottle"
if @args.bottle?
if f.bottle_unneeded?
ohai "#{f}: skipping unneeded bottle."
elsif f.bottle_disabled?
@ -204,7 +218,7 @@ module Homebrew
end
orig_message = message = `git log HEAD^.. --format=%B`
if issue && !ARGV.include?("--clean")
if issue && !@args.clean?
ohai "Patch closes issue ##{issue}"
close_message = "Closes ##{issue}."
# If this is a pull request, append a close message.
@ -216,7 +230,7 @@ module Homebrew
is_bumpable = false
end
is_bumpable = false if ARGV.include?("--clean")
is_bumpable = false if @args.clean?
is_bumpable = false if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]
if is_bumpable
@ -228,7 +242,7 @@ module Homebrew
odie "No version changes found for #{formula.name}" if bump_subject.nil?
unless orig_subject == bump_subject
ohai "New bump commit subject: #{bump_subject}"
pbcopy bump_subject unless ARGV.include? "--no-pbcopy"
pbcopy bump_subject unless @args.no_pbcopy?
message = "#{bump_subject}\n\n#{message}"
end
elsif bump_subject != orig_subject && !bump_subject.nil?
@ -237,7 +251,7 @@ module Homebrew
end
end
if message != orig_message && !ARGV.include?("--clean")
if message != orig_message && !@args.clean?
safe_system "git", "commit", "--amend", "--signoff", "--allow-empty", "-q", "-m", message
end
@ -248,7 +262,8 @@ module Homebrew
url
else
bottle_branch = "pull-bottle-#{issue}"
"https://github.com/#{GitHub.test_bot_user user}/homebrew-#{tap.repo}/compare/#{user}:master...pr-#{issue}"
bot_username = GitHub.test_bot_user(user, @args.test_bot_user)
"https://github.com/#{bot_username}/homebrew-#{tap.repo}/compare/#{user}:master...pr-#{issue}"
end
curl "--silent", "--fail", "--output", "/dev/null", "--head", bottle_commit_url
@ -261,7 +276,7 @@ module Homebrew
safe_system "git", "branch", "--quiet", "-D", bottle_branch
# Publish bottles on Bintray
unless ARGV.include? "--no-publish"
unless @args.no_publish?
published = publish_changed_formula_bottles(tap, changed_formulae_names)
bintray_published_formulae.concat(published)
end
@ -291,7 +306,7 @@ module Homebrew
changed_formulae_names.each do |name|
f = Formula[name]
next if f.bottle_unneeded? || f.bottle_disabled?
bintray_org = ARGV.value("bintray-org") || tap.user.downcase
bintray_org = @args.bintray_org || tap.user.downcase
next unless publish_bottle_file_on_bintray(f, bintray_org, bintray_creds)
published << f.full_name
end
@ -302,7 +317,7 @@ module Homebrew
end
def pull_patch(url, description = nil)
PatchPuller.new(url, description).pull_patch
PatchPuller.new(url, @args, description).pull_patch
end
class PatchPuller
@ -310,12 +325,13 @@ module Homebrew
attr_reader :patch_url
attr_reader :patchpath
def initialize(url, description = nil)
def initialize(url, args, description = nil)
@base_url = url
# GitHub provides commits/pull-requests raw patches using this URL.
@patch_url = url + ".patch"
@patchpath = HOMEBREW_CACHE + File.basename(patch_url)
@description = description
@args = args
end
def pull_patch
@ -338,7 +354,7 @@ module Homebrew
patch_args = []
# Normally we don't want whitespace errors, but squashing them can break
# patches so an option is provided to skip this step.
if ARGV.include?("--ignore-whitespace") || ARGV.include?("--clean")
if @args.ignore_whitespace? || @args.clean?
patch_args << "--whitespace=nowarn"
else
patch_args << "--whitespace=fix"
@ -351,7 +367,7 @@ module Homebrew
begin
safe_system "git", "am", *patch_args
rescue ErrorDuringExecution
if ARGV.include? "--resolve"
if @args.resolve?
odie "Patch failed to apply: try to resolve it."
else
system "git", "am", "--abort"
@ -464,7 +480,7 @@ module Homebrew
"https://api.bintray.com/content/#{bintray_org}/#{repo}/#{package}/#{version}/publish"
true
rescue => e
raise unless ARGV.include?("--warn-on-publish-failure")
raise unless @args.warn_on_publish_failure?
onoe e
false
end

View File

@ -5,10 +5,16 @@
#:
#: If `--markdown` is passed, output as a Markdown list.
require "cli_parser"
module Homebrew
module_function
def release_notes
args = Homebrew::CLI::Parser.parse do
switch "--markdown"
end
previous_tag = ARGV.named.first
previous_tag ||= Utils.popen_read("git tag --list --sort=-version:refname")
.lines.first.chomp
@ -28,7 +34,7 @@ module Homebrew
s.gsub(%r{.*Merge pull request #(\d+) from ([^/]+)/[^>]*(>>)*},
"https://github.com/Homebrew/brew/pull/\\1 (@\\2)")
end
if ARGV.include?("--markdown")
if args.markdown?
output.map! do |s|
/(.*\d)+ \(@(.+)\) - (.*)/ =~ s
"- [#{Regexp.last_match(3)}](#{Regexp.last_match(1)}) (@#{Regexp.last_match(2)})"

View File

@ -1,4 +1,4 @@
#: * `tests` [`--verbose`] [`--coverage`] [`--generic`] [`--no-compat`] [`--only=`<test_script>[`:`<line_number>]] [`--seed` <seed>] [`--online`] [`--official-cmd-taps`]:
#: * `tests` [`--verbose`] [`--coverage`] [`--generic`] [`--no-compat`] [`--only=`<test_script>[`:`<line_number>]] [`--seed=`<seed>] [`--online`] [`--official-cmd-taps`]:
#: Run Homebrew's unit and integration tests. If provided,
#: `--only=`<test_script> runs only <test_script>_spec.rb, and `--seed`
#: randomizes tests with the provided value instead of a random seed.
@ -15,6 +15,7 @@
#: If `--online` is passed, include tests that use the GitHub API and tests
#: that use any of the taps for official external commands.
require "cli_parser"
require "fileutils"
require "tap"
@ -22,6 +23,16 @@ module Homebrew
module_function
def tests
args = Homebrew::CLI::Parser.parse do
switch "--no-compat"
switch "--generic"
switch "-v", "--verbose"
switch "--coverage"
switch "--online"
flag "--only", required: true
flag "--seed", required: true
end
HOMEBREW_LIBRARY_PATH.cd do
ENV.delete("HOMEBREW_VERBOSE")
ENV.delete("VERBOSE")
@ -29,16 +40,16 @@ module Homebrew
ENV.delete("HOMEBREW_TEMP")
ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
ENV["HOMEBREW_DEVELOPER"] = "1"
ENV["HOMEBREW_NO_COMPAT"] = "1" if ARGV.include? "--no-compat"
ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if ARGV.include? "--generic"
ENV["HOMEBREW_NO_COMPAT"] = "1" if args.no_compat?
ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if args.generic?
if ARGV.include? "--online"
if args.online?
ENV["HOMEBREW_TEST_ONLINE"] = "1"
else
ENV["HOMEBREW_NO_GITHUB_API"] = "1"
end
if ARGV.include? "--coverage"
if args.coverage?
ENV["HOMEBREW_TESTS_COVERAGE"] = "1"
FileUtils.rm_f "test/coverage/.resultset.json"
end
@ -58,8 +69,8 @@ module Homebrew
parallel = true
files = if ARGV.value("only")
test_name, line = ARGV.value("only").split(":", 2)
files = if args.only
test_name, line = args.only.split(":", 2)
if line.nil?
Dir.glob("test/{#{test_name},#{test_name}/**/*}_spec.rb")
@ -84,7 +95,7 @@ module Homebrew
# Generate seed ourselves and output later to avoid multiple different
# seeds being output when running parallel tests.
seed = ARGV.include?("--seed") ? ARGV.next : rand(0xFFFF).to_i
seed = args.seed ? args.seed : rand(0xFFFF).to_i
args = ["-I", HOMEBREW_LIBRARY_PATH/"test"]
args += %W[

View File

@ -14,13 +14,22 @@
#: If `--keep-tmp` is passed, retain the temporary directory containing
#: the new repository clone.
require "cli_parser"
module Homebrew
module_function
def update_test
args = Homebrew::CLI::Parser.parse do
switch "--to-tag"
switch "--keep-tmp"
flag "--commit", required: true
flag "--before", required: true
end
ENV["HOMEBREW_UPDATE_TEST"] = "1"
if ARGV.include?("--to-tag")
if args.to_tag?
ENV["HOMEBREW_UPDATE_TO_TAG"] = "1"
branch = "stable"
else
@ -28,11 +37,11 @@ module Homebrew
end
cd HOMEBREW_REPOSITORY
start_commit = if commit = ARGV.value("commit")
start_commit = if commit = args.commit
commit
elsif date = ARGV.value("before")
elsif date = args.before
Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp
elsif ARGV.include?("--to-tag")
elsif args.to_tag?
tags = Utils.popen_read("git", "tag", "--list", "--sort=-version:refname")
previous_tag = tags.lines[1]
previous_tag ||= begin
@ -62,7 +71,7 @@ module Homebrew
puts "End commit: #{end_commit}"
mktemp("update-test") do |staging|
staging.retain! if ARGV.keep_tmp?
staging.retain! if args.keep_tmp?
curdir = Pathname.new(Dir.pwd)
oh1 "Setup test environment..."

View File

@ -74,7 +74,7 @@ class DevelopmentTools
def clang_build_version
@clang_build_version ||= begin
if (path = locate("clang")) &&
build_version = `#{path} --version`[/clang-(\d{2,})/, 1]
build_version = `#{path} --version`[%r{clang(-| version [^ ]+ \(tags/RELEASE_)(\d{2,})}, 2]
Version.new build_version
else
Version::NULL

View File

@ -11,12 +11,10 @@ module Homebrew
missing = {}
ff.each do |f|
missing_dependencies = f.missing_dependencies(hide: hide)
unless missing_dependencies.empty?
next if missing_dependencies.empty?
yield f.full_name, missing_dependencies if block_given?
missing[f.full_name] = missing_dependencies
end
end
missing
end

View File

@ -6,6 +6,13 @@ class AbstractDownloadStrategy
extend Forwardable
include FileUtils
module Pourable
def stage
ohai "Pouring #{cached_location.basename}"
super
end
end
attr_reader :meta, :name, :version, :resource
attr_reader :shutup
@ -15,6 +22,7 @@ class AbstractDownloadStrategy
@url = resource.url
@version = resource.version
@meta = resource.specs
extend Pourable if meta[:bottle]
end
# Download and cache the resource as {#cached_location}.
@ -442,14 +450,6 @@ class NoUnzipCurlDownloadStrategy < CurlDownloadStrategy
end
end
# This strategy extracts our binary packages.
class CurlBottleDownloadStrategy < CurlDownloadStrategy
def stage
ohai "Pouring #{cached_location.basename}"
super
end
end
# This strategy extracts local binary packages.
class LocalBottleDownloadStrategy < AbstractFileDownloadStrategy
attr_reader :cached_location
@ -457,11 +457,6 @@ class LocalBottleDownloadStrategy < AbstractFileDownloadStrategy
def initialize(path)
@cached_location = path
end
def stage
ohai "Pouring #{cached_location.basename}"
super
end
end
# S3DownloadStrategy downloads tarballs from AWS S3.
@ -473,17 +468,8 @@ end
# distribution. (It will work for public buckets as well.)
class S3DownloadStrategy < CurlDownloadStrategy
def _fetch
# Put the aws gem requirement here (vs top of file) so it's only
# a dependency of S3 users, not all Homebrew users
require "rubygems"
begin
require "aws-sdk-v1"
rescue LoadError
onoe "Install the aws-sdk gem into the gem repo used by brew."
raise
end
if @url !~ %r{^https?://([^.].*)\.s3\.amazonaws\.com/(.+)$}
if @url !~ %r{^https?://([^.].*)\.s3\.amazonaws\.com/(.+)$} &&
@url !~ %r{^s3://([^.].*?)/(.+)$}
raise "Bad S3 URL: " + @url
end
bucket = Regexp.last_match(1)
@ -492,12 +478,12 @@ class S3DownloadStrategy < CurlDownloadStrategy
ENV["AWS_ACCESS_KEY_ID"] = ENV["HOMEBREW_AWS_ACCESS_KEY_ID"]
ENV["AWS_SECRET_ACCESS_KEY"] = ENV["HOMEBREW_AWS_SECRET_ACCESS_KEY"]
obj = AWS::S3.new.buckets[bucket].objects[key]
begin
s3url = obj.url_for(:get)
rescue AWS::Errors::MissingCredentialsError
signer = Aws::S3::Presigner.new
s3url = signer.presigned_url :get_object, bucket: bucket, key: key
rescue Aws::Sigv4::Errors::MissingCredentialsError
ohai "AWS credentials missing, trying public URL instead."
s3url = obj.public_url
s3url = @url
end
curl_download s3url, to: temporary_path
@ -1116,6 +1102,9 @@ class DownloadStrategyDetector
def self.detect(url, strategy = nil)
if strategy.nil?
detect_from_url(url)
elsif strategy == S3DownloadStrategy
require_aws_sdk
strategy
elsif strategy.is_a?(Class) && strategy < AbstractDownloadStrategy
strategy
elsif strategy.is_a?(Symbol)
@ -1148,6 +1137,9 @@ class DownloadStrategyDetector
SubversionDownloadStrategy
when %r{^https?://(.+?\.)?sourceforge\.net/hgweb/}
MercurialDownloadStrategy
when %r{^s3://}
require_aws_sdk
S3DownloadStrategy
else
CurlDownloadStrategy
end
@ -1169,4 +1161,9 @@ class DownloadStrategyDetector
raise "Unknown download strategy #{symbol} was requested."
end
end
def self.require_aws_sdk
Homebrew.install_gem! "aws-sdk-s3", "~> 1.8"
require "aws-sdk-s3"
end
end

View File

@ -181,8 +181,7 @@ class TapFormulaAmbiguityError < RuntimeError
@name = name
@paths = paths
@formulae = paths.map do |path|
match = path.to_s.match(HOMEBREW_TAP_PATH_REGEX)
"#{Tap.fetch(match[:user], match[:repo])}/#{path.basename(".rb")}"
"#{Tap.from_path(path).name}/#{path.basename(".rb")}"
end
super <<~EOS

View File

@ -15,6 +15,7 @@ module HomebrewArgvExtension
--no-sandbox
--build-bottle
--force-bottle
--include-test
--verbose
--force
-i
@ -267,10 +268,6 @@ module HomebrewArgvExtension
include? "--fetch-HEAD"
end
def pry?
include?("--pry") || !ENV["HOMEBREW_PRY"].nil?
end
# eg. `foo -ns -i --bar` has three switches, n, s and i
def switch?(char)
return false if char.length > 1

View File

@ -5,10 +5,10 @@ class JavaRequirement < Requirement
end
# A strict Java 8 requirement (1.8) should prompt the user to install
# the legacy java8 cask because the current version, Java 9, is not
# completely backwards compatible, and contains breaking changes such as
# the legacy java8 cask because versions newer than Java 8 are not
# completely backwards compatible, and contain breaking changes such as
# strong encapsulation of JDK-internal APIs and a modified version scheme
# (9.0 not 1.9).
# (*.0 not 1.*).
def cask
if @version.nil? || @version.to_s.end_with?("+") ||
@version.to_f >= JAVA_CASK_MAP.keys.max.to_f
@ -22,7 +22,7 @@ class JavaRequirement < Requirement
JAVA_CASK_MAP = {
"1.8" => "caskroom/versions/java8",
"9.0" => "java",
"10.0" => "java",
}.freeze
def possible_javas

View File

@ -16,6 +16,7 @@ require "migrator"
require "linkage_checker"
require "extend/ENV"
require "language/python"
require "tab"
# A formula provides instructions and metadata for Homebrew to install a piece
# of software. Every Homebrew formula is a {Formula}.
@ -179,8 +180,8 @@ class Formula
@tap = if path == Formulary.core_path(name)
CoreTap.instance
elsif match = path.to_s.match(HOMEBREW_TAP_PATH_REGEX)
Tap.fetch(match[:user], match[:repo])
else
Tap.from_path(path)
end
@full_name = full_name_with_optional_tap(name)
@ -439,7 +440,6 @@ class Formula
# If at least one version of {Formula} is installed.
# @private
def any_version_installed?
require "tab"
installed_prefixes.any? { |keg| (keg/Tab::FILENAME).file? }
end
@ -1487,15 +1487,15 @@ class Formula
# Returns a list of Dependency objects that are required at runtime.
# @private
def runtime_dependencies
declared_runtime_dependencies | undeclared_runtime_dependencies
def runtime_dependencies(read_from_tab: true)
if read_from_tab &&
installed_prefix.directory? &&
(keg = Keg.new(installed_prefix)) &&
(tab_deps = keg.runtime_dependencies)
return tab_deps.map { |d| Dependency.new d["full_name"] }.compact
end
def declared_runtime_dependencies
recursive_dependencies do |_, dependency|
Dependency.prune if dependency.build?
Dependency.prune if !dependency.required? && build.without?(dependency)
end
declared_runtime_dependencies | undeclared_runtime_dependencies
end
def undeclared_runtime_dependencies
@ -1515,26 +1515,17 @@ class Formula
# installed
def missing_dependencies(hide: nil)
hide ||= []
missing_dependencies = recursive_dependencies do |dependent, dep|
if dep.build?
Dependency.prune
elsif dep.optional? || dep.recommended?
tab = Tab.for_formula(dependent)
Dependency.prune unless tab.with?(dep)
end
end
missing_dependencies.map!(&:to_formula)
missing_dependencies.select! do |d|
runtime_dependencies.map(&:to_formula).select do |d|
hide.include?(d.name) || d.installed_prefixes.empty?
end
missing_dependencies
rescue FormulaUnavailableError
[]
end
# @private
def to_hash
dependencies = deps
hsh = {
"name" => name,
"full_name" => full_name,
@ -1544,21 +1535,21 @@ class Formula
"aliases" => aliases,
"versions" => {
"stable" => stable&.version&.to_s,
"bottle" => bottle ? true : false,
"bottle" => !bottle.nil?,
"devel" => devel&.version&.to_s,
"head" => head&.version&.to_s,
},
"revision" => revision,
"version_scheme" => version_scheme,
"installed" => [],
"linked_keg" => (linked_version.to_s if linked_keg.exist?),
"linked_keg" => linked_version&.to_s,
"pinned" => pinned?,
"outdated" => outdated?,
"keg_only" => keg_only?,
"dependencies" => deps.map(&:name).uniq,
"recommended_dependencies" => deps.select(&:recommended?).map(&:name).uniq,
"optional_dependencies" => deps.select(&:optional?).map(&:name).uniq,
"build_dependencies" => deps.select(&:build?).map(&:name).uniq,
"dependencies" => dependencies.map(&:name).uniq,
"recommended_dependencies" => dependencies.select(&:recommended?).map(&:name).uniq,
"optional_dependencies" => dependencies.select(&:optional?).map(&:name).uniq,
"build_dependencies" => dependencies.select(&:build?).map(&:name).uniq,
"conflicts_with" => conflicts.map(&:name),
"caveats" => caveats,
}
@ -1587,7 +1578,7 @@ class Formula
"root_url" => bottle_spec.root_url,
}
bottle_info["files"] = {}
bottle_spec.collector.keys.each do |os| # rubocop:disable Performance/HashEachMethods
bottle_spec.collector.keys.each do |os|
checksum = bottle_spec.collector[os]
bottle_info["files"][os] = {
"url" => "#{bottle_spec.root_url}/#{Bottle::Filename.create(self, os, bottle_spec.rebuild)}",

View File

@ -34,7 +34,7 @@ class FormulaInstaller
attr_accessor :options, :build_bottle, :invalid_option_names
attr_accessor :installed_as_dependency, :installed_on_request, :link_keg
mode_attr_accessor :show_summary_heading, :show_header
mode_attr_accessor :build_from_source, :force_bottle
mode_attr_accessor :build_from_source, :force_bottle, :include_test
mode_attr_accessor :ignore_deps, :only_deps, :interactive, :git
mode_attr_accessor :verbose, :debug, :quieter
@ -47,6 +47,7 @@ class FormulaInstaller
@build_from_source = ARGV.build_from_source? || ARGV.build_all_from_source?
@build_bottle = false
@force_bottle = ARGV.force_bottle?
@include_test = ARGV.include?("--include-test")
@interactive = false
@git = false
@verbose = ARGV.verbose?
@ -224,17 +225,19 @@ class FormulaInstaller
message = <<~EOS
#{formula.name} #{formula.linked_version} is already installed
EOS
message += if formula.outdated? && !formula.head?
<<~EOS
if formula.outdated? && !formula.head?
message += <<~EOS
To upgrade to #{formula.pkg_version}, run `brew upgrade #{formula.name}`
EOS
elsif only_deps?
message = nil
else
# some other version is already installed *and* linked
<<~EOS
message += <<~EOS
To install #{formula.pkg_version}, first run `brew unlink #{formula.name}`
EOS
end
raise CannotInstallFormulaError, message
raise CannotInstallFormulaError, message if message
end
# Warn if a more recent version of this formula is available in the tap.
@ -436,10 +439,12 @@ class FormulaInstaller
build = effective_build_options_for(dependent)
install_bottle_for_dependent = install_bottle_for?(dependent, build)
if (req.optional? || req.recommended?) && build.without?(req)
if req.prune_from_option?(build)
Requirement.prune
elsif req.satisfied?
Requirement.prune
elsif include_test? && req.test?
next
elsif !runtime_requirements.include?(req) && install_bottle_for_dependent
Requirement.prune
else
@ -464,11 +469,13 @@ class FormulaInstaller
inherited_options.fetch(dependent.name, []),
)
if (dep.optional? || dep.recommended?) && build.without?(dep)
if dep.prune_from_option?(build)
Dependency.prune
elsif include_test? && dep.test? && !dep.installed?
Dependency.keep_but_prune_recursive_deps
elsif dep.build? && install_bottle_for?(dependent, build)
Dependency.prune
elsif dep.build? && dependent.installed?
elsif dep.prune_if_build_and_not_dependent?(dependent)
Dependency.prune
elsif dep.satisfied?(inherited_options[dep.name])
Dependency.skip

View File

@ -111,7 +111,8 @@ module Formulary
# The name of the formula is found between the last slash and the last hyphen.
formula_name = File.basename(bottle_name)[/(.+)-/, 1]
resource = Resource.new(formula_name) { url bottle_name }
downloader = CurlBottleDownloadStrategy.new resource.name, resource
resource.specs[:bottle] = true
downloader = CurlDownloadStrategy.new resource.name, resource
@bottle_filename = downloader.cached_location
cached = @bottle_filename.exist?
downloader.fetch

View File

@ -102,47 +102,30 @@ class Keg
#
# For efficiency, we don't bother trying to get complete data.
def self.find_some_installed_dependents(kegs)
# First, check in the tabs of installed Formulae.
kegs.each do |keg|
# Don't include dependencies of kegs that were in the given array.
dependents = keg.installed_dependents - kegs
dependents.map! { |d| "#{d.name} #{d.version}" }
return [keg], dependents if dependents.any?
end
# Some kegs won't have modern Tabs with the dependencies listed.
# In this case, fall back to Formula#missing_dependencies.
# Find formulae that didn't have dependencies saved in all of their kegs,
# so need them to be calculated now.
#
# This happens after the initial dependency check because it's sloooow.
remaining_formulae = Formula.installed.select do |f|
installed_kegs = f.installed_kegs
# Don't include dependencies of kegs that were in the given array.
next false if (installed_kegs - kegs).empty?
installed_kegs.any? { |k| Tab.for_keg(k).runtime_dependencies.nil? }
end
keg_names = kegs.map(&:name)
keg_names = kegs.select(&:optlinked?).map(&:name)
keg_formulae = []
kegs_by_source = kegs.group_by do |keg|
begin
# First, attempt to resolve the keg to a formula
# to get up-to-date name and tap information.
f = keg.to_formula
keg_formulae << f
[f.name, f.tap]
rescue FormulaUnavailableError
# If the formula for the keg can't be found,
# fall back to the information in the tab.
[keg.name, Tab.for_keg(keg).tap]
[keg.name, keg.tab.tap]
end
end
remaining_formulae.each do |dependent|
all_required_kegs = Set.new
all_dependents = []
# Don't include dependencies of kegs that were in the given array.
formulae_to_check = Formula.installed - keg_formulae
formulae_to_check.each do |dependent|
required = dependent.missing_dependencies(hide: keg_names)
required_kegs = required.map do |f|
f_kegs = kegs_by_source[[f.name, f.tap]]
next unless f_kegs
@ -150,12 +133,16 @@ class Keg
f_kegs.sort_by(&:version).last
end.compact
next unless required_kegs.any?
next if required_kegs.empty?
return required_kegs, [dependent.to_s]
all_required_kegs += required_kegs
all_dependents << dependent.to_s
end
nil
return if all_required_kegs.empty?
return if all_dependents.empty?
[all_required_kegs.to_a, all_dependents.sort]
end
# if path is a file in a keg then this will return the containing Keg object
@ -390,25 +377,6 @@ class Keg
Formulary.from_keg(self)
end
def installed_dependents
return [] unless optlinked?
tap = Tab.for_keg(self).source["tap"]
Keg.all.select do |keg|
tab = Tab.for_keg(keg)
next if tab.runtime_dependencies.nil?
tab.runtime_dependencies.any? do |dep|
# Resolve formula rather than directly comparing names
# in case of conflicts between formulae from different taps.
begin
dep_formula = Formulary.factory(dep["full_name"])
dep_formula == to_formula
rescue FormulaUnavailableError
next dep["full_name"] == "#{tap}/#{name}"
end
end
end
end
def oldname_opt_record
@oldname_opt_record ||= if (opt_dir = HOMEBREW_PREFIX/"opt").directory?
opt_dir.subdirs.detect do |dir|
@ -503,8 +471,16 @@ class Keg
@oldname_opt_record = nil
end
def tab
Tab.for_keg(self)
end
def runtime_dependencies
tab.runtime_dependencies
end
def aliases
Tab.for_keg(self).aliases || []
tab.aliases || []
end
def optlink(mode = OpenStruct.new)
@ -523,7 +499,7 @@ class Keg
def delete_pyc_files!
find { |pn| pn.delete if %w[.pyc .pyo].include?(pn.extname) }
find { |pn| pn.delete if pn.basename.to_s == "__pycache__" }
find { |pn| FileUtils.rm_rf pn if pn.basename.to_s == "__pycache__" }
end
private

View File

@ -63,7 +63,8 @@ class LinkageChecker
formula.build.without?(dep)
end
declared_deps = formula.deps.reject { |dep| filter_out.call(dep) }.map(&:name)
recursive_deps = keg.to_formula.declared_runtime_dependencies.map { |dep| dep.to_formula.name }
runtime_deps = keg.to_formula.declared_runtime_dependencies
recursive_deps = runtime_deps.map { |dep| dep.to_formula.name }
declared_dep_names = declared_deps.map { |dep| dep.split("/").last }
indirect_deps = []
undeclared_deps = []

View File

@ -56,17 +56,21 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note
## OFFICIAL EXTERNAL COMMANDS
* `bundle`:
Bundler for non-Ruby dependencies from Homebrew:
<https://github.com/Homebrew/homebrew-bundle>
<%= homebrew_bundle.join("\n ").strip %>
* `cask`:
Install macOS applications distributed as binaries:
<https://github.com/caskroom/homebrew-cask>
* `services`:
Integrates Homebrew formulae with macOS's `launchctl`(1) manager:
<https://github.com/Homebrew/homebrew-services>
Homebrew/homebrew-bundle <https://github.com/Homebrew/homebrew-bundle>
* `cask` [`--version` | `audit` | `cat` | `cleanup` | `create` | `doctor` | `edit` | `fetch` | `home` | `info`]:
Install macOS applications distributed as binaries.
Caskroom/homebrew-cask <https://github.com/caskroom/homebrew-cask>
<%= homebrew_services.join("\n ").strip %>
Homebrew/homebrew-services <https://github.com/Homebrew/homebrew-services>
## CUSTOM EXTERNAL COMMANDS
@ -242,6 +246,9 @@ can take several different forms:
This issue typically occurs when using FileVault or custom SSD
configurations.
* `HOMEBREW_UPGRADE_CLEANUP`:
If set, `brew upgrade` always assumes `--cleanup` has been passed.
* `HOMEBREW_VERBOSE`:
If set, Homebrew always assumes `--verbose` when running commands.

View File

@ -44,14 +44,19 @@ module RuboCop
end
# Separate dependencies according to precedence order:
# build-time > run-time > normal > recommended > optional
# build-time > test > normal > recommended > optional
def sort_dependencies_by_type(dependency_nodes)
unsorted_deps = dependency_nodes.to_a
ordered = []
ordered.concat(dependency_nodes.select { |dep| buildtime_dependency? dep }.to_a)
ordered.concat(dependency_nodes.select { |dep| runtime_dependency? dep }.to_a)
ordered.concat(dependency_nodes.reject { |dep| negate_normal_dependency? dep }.to_a)
ordered.concat(dependency_nodes.select { |dep| recommended_dependency? dep }.to_a)
ordered.concat(dependency_nodes.select { |dep| optional_dependency? dep }.to_a)
ordered.concat(unsorted_deps.select { |dep| buildtime_dependency? dep })
unsorted_deps -= ordered
ordered.concat(unsorted_deps.select { |dep| test_dependency? dep })
unsorted_deps -= ordered
ordered.concat(unsorted_deps.reject { |dep| negate_normal_dependency? dep })
unsorted_deps -= ordered
ordered.concat(unsorted_deps.select { |dep| recommended_dependency? dep })
unsorted_deps -= ordered
ordered.concat(unsorted_deps.select { |dep| optional_dependency? dep })
end
# `depends_on :apple if build.with? "foo"` should always be defined
@ -106,11 +111,11 @@ module RuboCop
def_node_search :recommended_dependency?, "(sym :recommended)"
def_node_search :runtime_dependency?, "(sym :run)"
def_node_search :test_dependency?, "(sym :test)"
def_node_search :optional_dependency?, "(sym :optional)"
def_node_search :negate_normal_dependency?, "(sym {:build :recommended :run :optional})"
def_node_search :negate_normal_dependency?, "(sym {:build :recommended :test :optional})"
# Node pattern method to extract `name` in `depends_on :name`
def_node_search :dependency_name_node, <<~EOS

View File

@ -171,7 +171,7 @@ module RuboCop
when :required
type_match = required_dependency?(node)
name_match ||= required_dependency_name?(node, name) if type_match
when :build, :optional, :recommended, :run
when :build, :test, :optional, :recommended
type_match = dependency_type_hash_match?(node, type)
name_match ||= dependency_name_hash_match?(node, name) if type_match
when :any

View File

@ -85,10 +85,10 @@ fi
case "$(lowercase "$SCM_FILE")" in
git)
[[ -n "$HOMEBREW_GIT" ]] && safe_exec "$(which "$HOMEBREW_GIT")" "$@"
[[ -n "$HOMEBREW_GIT" ]] && safe_exec "$(type -P "$HOMEBREW_GIT")" "$@"
;;
svn)
[[ -n "$HOMEBREW_SVN" ]] && safe_exec "$(which "$HOMEBREW_SVN")" "$@"
[[ -n "$HOMEBREW_SVN" ]] && safe_exec "$(type -P "$HOMEBREW_SVN")" "$@"
;;
esac
@ -99,7 +99,7 @@ brew_repo_version="$(quiet_safe_cd "$SCM_DIR/../../../../bin" && pwd -P)/$SCM_FI
safe_exec "$brew_repo_version" "$@"
IFS=$'\n'
for path in $(/usr/bin/which -a "$SCM_FILE" 2>/dev/null)
for path in $(type -aP "$SCM_FILE")
do
if [[ "$path" != "/usr/bin/$SCM_FILE" ]]
then

View File

@ -1,8 +1,8 @@
#!/bin/bash
POD2MAN="$(/usr/bin/which pod2man5.18 ||
/usr/bin/which pod2man5.16 ||
/usr/bin/which pod2man5.12 ||
/usr/bin/which "$HOMEBREW_PREFIX/opt/pod2man/bin/pod2man" ||
POD2MAN="$(type -P pod2man5.18 ||
type -P pod2man5.16 ||
type -P pod2man5.12 ||
type -P "$HOMEBREW_PREFIX/opt/pod2man/bin/pod2man" ||
echo /usr/bin/pod2man)"
exec "$POD2MAN" "$@"

View File

@ -283,13 +283,14 @@ class Bottle
@name = formula.name
@resource = Resource.new
@resource.owner = formula
@resource.specs[:bottle] = true
@spec = spec
checksum, tag = spec.checksum_for(Utils::Bottles.tag)
filename = Filename.create(formula, tag, spec.rebuild)
@resource.url(build_url(spec.root_url, filename))
@resource.download_strategy = CurlBottleDownloadStrategy
@resource.url(build_url(spec.root_url, filename),
select_download_strategy(spec.root_url_specs))
@resource.version = formula.pkg_version
@resource.checksum = checksum
@prefix = spec.prefix
@ -315,6 +316,11 @@ class Bottle
def build_url(root_url, filename)
"#{root_url}/#{filename}"
end
def select_download_strategy(specs)
specs[:using] ||= DownloadStrategyDetector.detect(@spec.root_url)
specs
end
end
class BottleSpecification
@ -324,20 +330,22 @@ class BottleSpecification
attr_rw :prefix, :cellar, :rebuild
attr_accessor :tap
attr_reader :checksum, :collector
attr_reader :checksum, :collector, :root_url_specs
def initialize
@rebuild = 0
@prefix = DEFAULT_PREFIX
@cellar = DEFAULT_CELLAR
@collector = Utils::Bottles::Collector.new
@root_url_specs = {}
end
def root_url(var = nil)
def root_url(var = nil, specs = {})
if var.nil?
@root_url ||= "#{DEFAULT_DOMAIN}/#{Utils::Bottles::Bintray.repository(tap)}"
else
@root_url = var
@root_url_specs.merge!(specs)
end
end

View File

@ -183,6 +183,7 @@ class SystemConfig
HOMEBREW_LIBRARY
HOMEBREW_MACOS_VERSION
HOMEBREW_RUBY_PATH
HOMEBREW_RUBY_WARNINGS
HOMEBREW_SYSTEM
HOMEBREW_OS_VERSION
HOMEBREW_PATH
@ -199,10 +200,13 @@ class SystemConfig
if defaults_hash[:HOMEBREW_CELLAR] != HOMEBREW_CELLAR.to_s
f.puts "HOMEBREW_CELLAR: #{HOMEBREW_CELLAR}"
end
if defaults_hash[:HOMEBREW_CACHE] != HOMEBREW_CACHE.to_s
f.puts "HOMEBREW_CACHE: #{HOMEBREW_CACHE}"
end
ENV.sort.each do |key, value|
next unless key.start_with?("HOMEBREW_")
next if boring_keys.include?(key)
next if defaults_hash[key.to_sym] == value
next if defaults_hash[key.to_sym]
value = "set" if key =~ /(cookie|key|token|password)/i
f.puts "#{key}: #{value}"
end
@ -210,7 +214,17 @@ class SystemConfig
f.puts "Homebrew Ruby: #{describe_homebrew_ruby}"
f.puts "GCC-4.0: build #{gcc_4_0}" unless gcc_4_0.null?
f.puts "GCC-4.2: build #{gcc_4_2}" unless gcc_4_2.null?
f.puts "Clang: #{clang.null? ? "N/A" : "#{clang} build #{clang_build}"}"
f.print "Clang: "
if clang.null?
f.puts "N/A"
else
f.print "#{clang} build "
if clang_build.null?
f.puts "(parse error)"
else
f.puts clang_build
end
end
f.puts "Git: #{describe_git}"
f.puts "Curl: #{describe_curl}"
f.puts "Perl: #{describe_perl}"

View File

@ -17,6 +17,7 @@ class Tab < OpenStruct
# Instantiates a Tab for a new installation of a formula.
def self.create(formula, compiler, stdlib)
build = formula.build
runtime_deps = formula.runtime_dependencies(read_from_tab: false)
attributes = {
"homebrew_version" => HOMEBREW_VERSION,
"used_options" => build.used_options.as_flags,
@ -32,18 +33,18 @@ class Tab < OpenStruct
"compiler" => compiler,
"stdlib" => stdlib,
"aliases" => formula.aliases,
"runtime_dependencies" => formula.runtime_dependencies.map do |dep|
"runtime_dependencies" => runtime_deps.map do |dep|
f = dep.to_formula
{ "full_name" => f.full_name, "version" => f.version.to_s }
end,
"source" => {
"path" => formula.specified_path.to_s,
"tap" => formula.tap ? formula.tap.name : nil,
"tap" => formula.tap&.name,
"spec" => formula.active_spec_sym.to_s,
"versions" => {
"stable" => formula.stable ? formula.stable.version.to_s : nil,
"devel" => formula.devel ? formula.devel.version.to_s : nil,
"head" => formula.head ? formula.head.version.to_s : nil,
"stable" => formula.stable&.version.to_s,
"devel" => formula.devel&.version.to_s,
"head" => formula.head&.version.to_s,
"version_scheme" => formula.version_scheme,
},
},
@ -66,7 +67,7 @@ class Tab < OpenStruct
attributes["source"] ||= {}
tapped_from = attributes["tapped_from"]
unless tapped_from.nil? || tapped_from == "path or URL"
if !tapped_from.nil? && tapped_from != "path or URL"
attributes["source"]["tap"] = attributes.delete("tapped_from")
end
@ -156,12 +157,12 @@ class Tab < OpenStruct
tab.unused_options = f.options.as_flags
tab.source = {
"path" => f.specified_path.to_s,
"tap" => f.tap ? f.tap.name : f.tap,
"tap" => f.tap&.name,
"spec" => f.active_spec_sym.to_s,
"versions" => {
"stable" => f.stable ? f.stable.version.to_s : nil,
"devel" => f.devel ? f.devel.version.to_s : nil,
"head" => f.head ? f.head.version.to_s : nil,
"stable" => f.stable&.version.to_s,
"devel" => f.devel&.version.to_s,
"head" => f.head&.version.to_s,
"version_scheme" => f.version_scheme,
},
}
@ -185,7 +186,7 @@ class Tab < OpenStruct
"stdlib" => nil,
"compiler" => DevelopmentTools.default_compiler,
"aliases" => [],
"runtime_dependencies" => [],
"runtime_dependencies" => nil,
"source" => {
"path" => nil,
"tap" => nil,

View File

@ -39,7 +39,7 @@ class Tap
end
def self.from_path(path)
match = path.to_s.match(HOMEBREW_TAP_PATH_REGEX)
match = File.expand_path(path).match(HOMEBREW_TAP_PATH_REGEX)
raise "Invalid tap path '#{path}'" unless match
fetch(match[:user], match[:repo])
rescue
@ -543,11 +543,7 @@ end
# A specialized {Tap} class for the core formulae
class CoreTap < Tap
def default_remote
if OS.mac? || ENV["HOMEBREW_FORCE_HOMEBREW_ORG"]
"https://github.com/Homebrew/homebrew-core".freeze
else
"https://github.com/Linuxbrew/homebrew-core".freeze
end
end
# @private

View File

@ -2,6 +2,7 @@ require "extend/ARGV"
describe HomebrewArgvExtension do
subject { argv.extend(described_class) }
let(:argv) { ["mxcl"] }
describe "#formulae" do
@ -26,7 +27,7 @@ describe HomebrewArgvExtension do
describe "#kegs" do
context "when there are matching Kegs" do
before(:each) do
before do
keg = HOMEBREW_CELLAR + "mxcl/10.0"
keg.mkpath
end

View File

@ -2,6 +2,7 @@ require "extend/ENV"
shared_examples EnvActivation do
subject { env.extend(described_class) }
let(:env) { {}.extend(EnvActivation) }
it "supports switching compilers" do

View File

@ -17,6 +17,7 @@ describe "Bash" do
context "brew" do
subject { HOMEBREW_LIBRARY_PATH.parent.parent/"bin/brew" }
it { is_expected.to have_valid_bash_syntax }
end
@ -33,6 +34,7 @@ describe "Bash" do
context "Bash completion" do
subject { HOMEBREW_LIBRARY_PATH.parent.parent/"completions/bash/brew" }
it { is_expected.to have_valid_bash_syntax }
end

View File

@ -43,7 +43,7 @@ describe BuildEnvironment do
subject { double.extend(described_class) }
context "single argument" do
before(:each) do
before do
subject.instance_eval do
env :userpaths
end
@ -53,7 +53,7 @@ describe BuildEnvironment do
end
context "multiple arguments" do
before(:each) do
before do
subject.instance_eval do
env :userpaths, :std
end

View File

@ -6,6 +6,7 @@ describe BuildOptions do
alias_matcher :be_built_without, :be_without
subject { described_class.new(args, opts) }
let(:bad_build) { described_class.new(bad_args, opts) }
let(:args) { Options.create(%w[--with-foo --with-bar --without-qux]) }
let(:opts) { Options.create(%w[--with-foo --with-bar --without-baz --without-qux]) }

View File

@ -5,7 +5,7 @@ describe "Accessibility Access", :cask do
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:installer) { Hbc::Installer.new(cask, command: fake_system_command) }
before(:each) do
before do
allow(MacOS).to receive(:version).and_return(MacOS::Version.new(macos_version))
allow(installer).to receive(:bundle_identifier).and_return("com.example.BasicCask")
end

View File

@ -10,7 +10,7 @@ describe Hbc::Artifact::App, :cask do
let(:install_phase) { app.install_phase(command: command, force: force) }
let(:uninstall_phase) { app.uninstall_phase(command: command, force: force) }
before(:each) do
before do
InstallHelper.install_without_artifacts(cask)
end
@ -58,7 +58,7 @@ describe Hbc::Artifact::App, :cask do
end
describe "when the target already exists" do
before(:each) do
before do
target_path.mkpath
end
@ -76,7 +76,7 @@ describe Hbc::Artifact::App, :cask do
describe "given the force option" do
let(:force) { true }
before(:each) do
before do
allow(Hbc::Utils).to receive(:current_user).and_return("fake_user")
end
@ -104,7 +104,7 @@ describe Hbc::Artifact::App, :cask do
end
describe "target is user-owned but contains read-only files" do
before(:each) do
before do
FileUtils.touch "#{target_path}/foo"
FileUtils.chmod 0555, target_path
end
@ -137,7 +137,7 @@ describe Hbc::Artifact::App, :cask do
expect(contents_path).to exist
end
after(:each) do
after do
FileUtils.chmod 0755, target_path
end
end
@ -147,7 +147,7 @@ describe Hbc::Artifact::App, :cask do
describe "when the target is a broken symlink" do
let(:deleted_path) { cask.staged_path.join("Deleted.app") }
before(:each) do
before do
deleted_path.mkdir
File.symlink(deleted_path, target_path)
deleted_path.rmdir

View File

@ -7,7 +7,7 @@ describe Hbc::Artifact::Binary, :cask do
let(:artifacts) { cask.artifacts.select { |a| a.is_a?(described_class) } }
let(:expected_path) { Hbc::Config.global.binarydir.join("binary") }
after(:each) do
after do
FileUtils.rm expected_path if expected_path.exist?
end

View File

@ -2,7 +2,7 @@ describe Hbc::Artifact::Pkg, :cask do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-installable")) }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
before(:each) do
before do
InstallHelper.install_without_artifacts(cask)
end

View File

@ -12,7 +12,7 @@ describe Hbc::Artifact::Suite, :cask do
let(:target_path) { Hbc::Config.global.appdir.join("Caffeine") }
let(:source_path) { cask.staged_path.join("Caffeine") }
before(:each) do
before do
InstallHelper.install_without_artifacts(cask)
end

View File

@ -16,7 +16,7 @@ describe Hbc::Artifact::App, :cask do
let(:source_path_pro) { cask.staged_path.join("Caffeine Pro.app") }
let(:target_path_pro) { Hbc::Config.global.appdir.join("Caffeine Pro.app") }
before(:each) do
before do
InstallHelper.install_without_artifacts(cask)
end

View File

@ -5,7 +5,7 @@ describe Hbc::Artifact::Zap, :cask do
cask.artifacts.find { |a| a.is_a?(described_class) }
}
before(:each) do
before do
InstallHelper.install_without_artifacts(cask)
end

View File

@ -79,33 +79,60 @@ describe Hbc::Audit, :cask do
end
describe "#run!" do
let(:cask) { Hbc::CaskLoader.load(cask_token) }
subject { audit.run! }
let(:cask) { Hbc::CaskLoader.load(cask_token) }
describe "required stanzas" do
%w[version sha256 url name homepage].each do |stanza|
context "when missing #{stanza}" do
let(:cask_token) { "missing-#{stanza}" }
it { is_expected.to fail_with(/#{stanza} stanza is required/) }
end
end
end
describe "pkg allow_untrusted checks" do
let(:error_msg) { "allow_untrusted is not permitted in official Homebrew-Cask taps" }
context "when the Cask has no pkg stanza" do
let(:cask_token) { "basic-cask" }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the Cask does not have allow_untrusted" do
let(:cask_token) { "with-uninstall-pkgutil" }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the Cask has allow_untrusted" do
let(:cask_token) { "with-allow-untrusted" }
it { is_expected.to warn_with(error_msg) }
end
end
describe "preflight stanza checks" do
let(:error_msg) { "only a single preflight stanza is allowed" }
context "when the cask has no preflight stanza" do
context "when the Cask has no preflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has only one preflight stanza" do
context "when the Cask has only one preflight stanza" do
let(:cask_token) { "with-preflight" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has multiple preflight stanzas" do
context "when the Cask has multiple preflight stanzas" do
let(:cask_token) { "with-preflight-multi" }
it { is_expected.to warn_with(error_msg) }
end
end
@ -113,18 +140,21 @@ describe Hbc::Audit, :cask do
describe "uninstall_postflight stanza checks" do
let(:error_msg) { "only a single postflight stanza is allowed" }
context "when the cask has no postflight stanza" do
context "when the Cask has no postflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has only one postflight stanza" do
context "when the Cask has only one postflight stanza" do
let(:cask_token) { "with-postflight" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has multiple postflight stanzas" do
context "when the Cask has multiple postflight stanzas" do
let(:cask_token) { "with-postflight-multi" }
it { is_expected.to warn_with(error_msg) }
end
end
@ -132,18 +162,21 @@ describe Hbc::Audit, :cask do
describe "uninstall stanza checks" do
let(:error_msg) { "only a single uninstall stanza is allowed" }
context "when the cask has no uninstall stanza" do
context "when the Cask has no uninstall stanza" do
let(:cask_token) { "with-zap-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has only one uninstall stanza" do
context "when the Cask has only one uninstall stanza" do
let(:cask_token) { "with-uninstall-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has multiple uninstall stanzas" do
context "when the Cask has multiple uninstall stanzas" do
let(:cask_token) { "with-uninstall-multi" }
it { is_expected.to warn_with(error_msg) }
end
end
@ -151,18 +184,21 @@ describe Hbc::Audit, :cask do
describe "uninstall_preflight stanza checks" do
let(:error_msg) { "only a single uninstall_preflight stanza is allowed" }
context "when the cask has no uninstall_preflight stanza" do
context "when the Cask has no uninstall_preflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has only one uninstall_preflight stanza" do
context "when the Cask has only one uninstall_preflight stanza" do
let(:cask_token) { "with-uninstall-preflight" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has multiple uninstall_preflight stanzas" do
context "when the Cask has multiple uninstall_preflight stanzas" do
let(:cask_token) { "with-uninstall-preflight-multi" }
it { is_expected.to warn_with(error_msg) }
end
end
@ -170,18 +206,21 @@ describe Hbc::Audit, :cask do
describe "uninstall_postflight stanza checks" do
let(:error_msg) { "only a single uninstall_postflight stanza is allowed" }
context "when the cask has no uninstall_postflight stanza" do
context "when the Cask has no uninstall_postflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has only one uninstall_postflight stanza" do
context "when the Cask has only one uninstall_postflight stanza" do
let(:cask_token) { "with-uninstall-postflight" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has multiple uninstall_postflight stanzas" do
context "when the Cask has multiple uninstall_postflight stanzas" do
let(:cask_token) { "with-uninstall-postflight-multi" }
it { is_expected.to warn_with(error_msg) }
end
end
@ -189,18 +228,21 @@ describe Hbc::Audit, :cask do
describe "zap stanza checks" do
let(:error_msg) { "only a single zap stanza is allowed" }
context "when the cask has no zap stanza" do
context "when the Cask has no zap stanza" do
let(:cask_token) { "with-uninstall-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has only one zap stanza" do
context "when the Cask has only one zap stanza" do
let(:cask_token) { "with-zap-rmdir" }
it { should_not warn_with(error_msg) }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the cask has multiple zap stanzas" do
context "when the Cask has multiple zap stanzas" do
let(:cask_token) { "with-zap-multi" }
it { is_expected.to warn_with(error_msg) }
end
end
@ -210,28 +252,33 @@ describe Hbc::Audit, :cask do
context "when version is 'latest'" do
let(:cask_token) { "version-latest-string" }
it { is_expected.to fail_with(error_msg) }
end
context "when version is :latest" do
let(:cask_token) { "version-latest-with-checksum" }
it { should_not fail_with(error_msg) }
it { is_expected.not_to fail_with(error_msg) }
end
end
describe "sha256 checks" do
context "when version is :latest and sha256 is not :no_check" do
let(:cask_token) { "version-latest-with-checksum" }
it { is_expected.to fail_with("you should use sha256 :no_check when version is :latest") }
end
context "when sha256 is not a legal SHA-256 digest" do
let(:cask_token) { "invalid-sha256" }
it { is_expected.to fail_with("sha256 string must be of 64 hexadecimal characters") }
end
context "when sha256 is sha256 for empty string" do
let(:cask_token) { "sha256-for-empty-string" }
it { is_expected.to fail_with(/cannot use the sha256 for an empty string/) }
end
end
@ -239,22 +286,26 @@ describe Hbc::Audit, :cask do
describe "appcast checks" do
context "when appcast has no sha256" do
let(:cask_token) { "appcast-missing-checkpoint" }
it { is_expected.to fail_with(/checkpoint sha256 is required for appcast/) }
end
context "when appcast checkpoint is not a string of 64 hexadecimal characters" do
let(:cask_token) { "appcast-invalid-checkpoint" }
it { is_expected.to fail_with(/string must be of 64 hexadecimal characters/) }
end
context "when appcast checkpoint is sha256 for empty string" do
let(:cask_token) { "appcast-checkpoint-sha256-for-empty-string" }
it { is_expected.to fail_with(/cannot use the sha256 for an empty string/) }
end
context "when appcast checkpoint is valid sha256" do
let(:cask_token) { "appcast-valid-checkpoint" }
it { should_not fail_with(/appcast :checkpoint/) }
it { is_expected.not_to fail_with(/appcast :checkpoint/) }
end
context "when verifying appcast HTTP code" do
@ -279,11 +330,13 @@ describe Hbc::Audit, :cask do
context "when HTTP code is 200" do
let(:stdout) { "200" }
it { should_not warn_with(wrong_code_msg) }
it { is_expected.not_to warn_with(wrong_code_msg) }
end
context "when HTTP code is not 200" do
let(:stdout) { "404" }
it { is_expected.to warn_with(wrong_code_msg) }
end
end
@ -326,14 +379,16 @@ describe Hbc::Audit, :cask do
context "when appcast checkpoint is out of date" do
let(:actual_checkpoint) { "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }
it { is_expected.to warn_with(mismatch_msg) }
it { should_not warn_with(curl_error_msg) }
it { is_expected.not_to warn_with(curl_error_msg) }
end
context "when appcast checkpoint is up to date" do
let(:actual_checkpoint) { expected_checkpoint }
it { should_not warn_with(mismatch_msg) }
it { should_not warn_with(curl_error_msg) }
it { is_expected.not_to warn_with(mismatch_msg) }
it { is_expected.not_to warn_with(curl_error_msg) }
end
end
@ -349,44 +404,95 @@ describe Hbc::Audit, :cask do
end
end
describe "GitHub releases appcast check" do
let(:error_msg) { /Cask uses GitHub releases/ }
context "when the Cask does not use GitHub releases" do
let(:cask_token) { "basic-cask" }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the Cask uses GitHub releases and has an appcast" do
let(:cask_token) { "github-with-appcast" }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the Cask uses GitHub releases and does not have an appcast" do
let(:cask_token) { "github-without-appcast" }
it { is_expected.to warn_with(error_msg) }
end
end
describe "latest with appcast checks" do
let(:error_msg) { "Casks with an appcast should not use version :latest" }
context "when the Cask is :latest and does not have an appcast" do
let(:cask_token) { "version-latest" }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the Cask is versioned and has an appcast" do
let(:cask_token) { "with-appcast" }
it { is_expected.not_to warn_with(error_msg) }
end
context "when the Cask is :latest and has an appcast" do
let(:cask_token) { "latest-with-appcast" }
it { is_expected.to warn_with(error_msg) }
end
end
describe "preferred download URL formats" do
let(:warning_msg) { /URL format incorrect/ }
context "with incorrect SourceForge URL format" do
let(:cask_token) { "sourceforge-incorrect-url-format" }
it { is_expected.to warn_with(warning_msg) }
end
context "with correct SourceForge URL format" do
let(:cask_token) { "sourceforge-correct-url-format" }
it { should_not warn_with(warning_msg) }
it { is_expected.not_to warn_with(warning_msg) }
end
context "with correct SourceForge URL format for version :latest" do
let(:cask_token) { "sourceforge-version-latest-correct-url-format" }
it { should_not warn_with(warning_msg) }
it { is_expected.not_to warn_with(warning_msg) }
end
context "with incorrect OSDN URL format" do
let(:cask_token) { "osdn-incorrect-url-format" }
it { is_expected.to warn_with(warning_msg) }
end
context "with correct OSDN URL format" do
let(:cask_token) { "osdn-correct-url-format" }
it { should_not warn_with(warning_msg) }
it { is_expected.not_to warn_with(warning_msg) }
end
end
describe "generic artifact checks" do
context "with relative target" do
let(:cask_token) { "generic-artifact-relative-target" }
it { is_expected.to fail_with(/target must be absolute path for Generic Artifact/) }
end
context "with absolute target" do
let(:cask_token) { "generic-artifact-absolute-target" }
it { should_not fail_with(/target required for Generic Artifact/) }
it { is_expected.not_to fail_with(/target required for Generic Artifact/) }
end
end
@ -418,12 +524,14 @@ describe Hbc::Audit, :cask do
context "when cask token conflicts with a core formula" do
let(:formula_names) { %w[with-binary other-formula] }
it { is_expected.to warn_with(/possible duplicate/) }
end
context "when cask token does not conflict with a core formula" do
let(:formula_names) { %w[other-formula] }
it { should_not warn_with(/possible duplicate/) }
it { is_expected.not_to warn_with(/possible duplicate/) }
end
end
@ -440,7 +548,7 @@ describe Hbc::Audit, :cask do
expect(verify).to receive(:all)
end
it { should_not fail_with(/#{error_msg}/) }
it { is_expected.not_to fail_with(/#{error_msg}/) }
end
context "when download fails" do
@ -463,6 +571,7 @@ describe Hbc::Audit, :cask do
context "when an exception is raised" do
let(:cask) { instance_double(Hbc::Cask) }
before do
expect(cask).to receive(:version).and_raise(StandardError.new)
end

View File

@ -101,9 +101,10 @@ describe Hbc::Cask, :cask do
end
describe "versioned casks" do
let(:cask) { described_class.new("basic-cask") }
subject { cask.outdated_versions }
let(:cask) { described_class.new("basic-cask") }
shared_examples "versioned casks" do |tap_version, expectations|
expectations.each do |installed_versions, expected_output|
context "when versions #{installed_versions.inspect} are installed and the tap version is #{tap_version}" do
@ -139,6 +140,7 @@ describe Hbc::Cask, :cask do
expectations.each do |installed_version, expected_output|
context "when versions #{installed_version} are installed and the tap version is #{tap_version}, #{greedy ? "" : "not"} greedy" do
subject { cask.outdated_versions greedy }
it {
allow(cask).to receive(:versions).and_return(installed_version)
allow(cask).to receive(:version).and_return(Hbc::DSL::Version.new(tap_version))

View File

@ -1,12 +1,12 @@
require_relative "shared_examples/invalid_option"
describe Hbc::CLI::Cleanup, :cask do
subject { described_class.new(*cask_tokens, cache_location: cache_location) }
let(:cache_location) { Pathname.new(Dir.mktmpdir).realpath }
let(:outdated_only) { false }
subject { described_class.new(*cask_tokens, cache_location: cache_location) }
before(:each) do
before do
allow_any_instance_of(described_class).to receive(:outdated_only?).and_return(outdated_only)
end

View File

@ -2,7 +2,7 @@ require_relative "shared_examples/requires_cask_token"
require_relative "shared_examples/invalid_option"
describe Hbc::CLI::Create, :cask do
around(:each) do |example|
around do |example|
begin
example.run
ensure
@ -12,7 +12,7 @@ describe Hbc::CLI::Create, :cask do
end
end
before(:each) do
before do
allow_any_instance_of(described_class).to receive(:exec_editor)
end

View File

@ -2,7 +2,7 @@ require_relative "shared_examples/requires_cask_token"
require_relative "shared_examples/invalid_option"
describe Hbc::CLI::Edit, :cask do
before(:each) do
before do
allow_any_instance_of(described_class).to receive(:exec_editor)
end

View File

@ -49,7 +49,7 @@ describe Hbc::CLI::Info, :cask do
end
end
it "should print caveats if the Cask provided one" do
it "prints caveats if the Cask provided one" do
expect {
described_class.run("with-caveats")
}.to output(<<~EOS).to_stdout
@ -75,7 +75,7 @@ describe Hbc::CLI::Info, :cask do
EOS
end
it 'should not print "Caveats" section divider if the caveats block has no output' do
it 'does not print "Caveats" section divider if the caveats block has no output' do
expect {
described_class.run("with-conditional-caveats")
}.to output(<<~EOS).to_stdout

View File

@ -47,7 +47,7 @@ describe Hbc::CLI::List, :cask do
EOS
}
before(:each) do
before do
casks.map(&Hbc::CaskLoader.method(:load)).each(&InstallHelper.method(:install_with_caskfile))
end

View File

@ -1,7 +1,7 @@
require_relative "shared_examples/invalid_option"
describe Hbc::CLI::Search, :cask do
before(:each) do
before do
allow(Tty).to receive(:width).and_return(0)
end

View File

@ -92,6 +92,7 @@ describe Hbc::CLI::Style, :cask do
context "when at least one cask token is a path that exists" do
let(:tokens) { ["adium", "Casks/dropbox.rb"] }
before do
allow(File).to receive(:exist?).and_return(false, true)
end
@ -103,6 +104,7 @@ describe Hbc::CLI::Style, :cask do
context "when no cask tokens are paths that exist" do
let(:tokens) { %w[adium dropbox] }
before do
allow(File).to receive(:exist?).and_return(false)
end
@ -123,11 +125,13 @@ describe Hbc::CLI::Style, :cask do
context "when fix? is true" do
let(:fix) { true }
it { is_expected.to include("--auto-correct") }
end
context "when fix? is false" do
let(:fix) { false }
it { is_expected.not_to include("--auto-correct") }
end
end
@ -140,9 +144,10 @@ describe Hbc::CLI::Style, :cask do
describe "#autocorrect_args" do
subject { cli.autocorrect_args }
let(:default_args) { ["--format", "simple"] }
it "should add --auto-correct to default args" do
it "adds --auto-correct to default args" do
allow(cli).to receive(:default_args).and_return(default_args)
expect(subject).to include("--auto-correct", *default_args)
end

View File

@ -105,7 +105,7 @@ describe Hbc::CLI::Uninstall, :cask do
}
let(:caskroom_path) { Hbc.caskroom.join(token).tap(&:mkpath) }
before(:each) do
before do
timestamped_versions.each do |timestamped_version|
caskroom_path.join(".metadata", *timestamped_version, "Casks").tap(&:mkpath)
.join("#{token}.rb").open("w") do |caskfile|

View File

@ -13,7 +13,7 @@ describe Hbc::CLI::Upgrade, :cask do
]
}
before(:example) do
before do
installed.each { |cask| Hbc::CLI::Install.run(cask) }
allow_any_instance_of(described_class).to receive(:verbose?).and_return(true)
@ -176,7 +176,7 @@ describe Hbc::CLI::Upgrade, :cask do
]
}
before(:example) do
before do
installed.each { |cask| Hbc::CLI::Install.run(cask) }
allow_any_instance_of(described_class).to receive(:verbose?).and_return(true)
@ -201,7 +201,7 @@ describe Hbc::CLI::Upgrade, :cask do
expect(will_fail_if_upgraded).to be_installed
expect(will_fail_if_upgraded_path).to be_a_file
expect(will_fail_if_upgraded.versions).to include("1.2.2")
expect(will_fail_if_upgraded.staged_path).to_not exist
expect(will_fail_if_upgraded.staged_path).not_to exist
end
it "does not restore the old Cask if the upgrade failed pre-install" do
@ -219,7 +219,7 @@ describe Hbc::CLI::Upgrade, :cask do
expect(bad_checksum).to be_installed
expect(bad_checksum_path).to be_a_directory
expect(bad_checksum.versions).to include("1.2.2")
expect(bad_checksum.staged_path).to_not exist
expect(bad_checksum.staged_path).not_to exist
end
end
end

View File

@ -10,6 +10,7 @@ describe "Satisfy Dependencies and Requirements", :cask do
describe "depends_on cask" do
context "when depends_on cask is cyclic" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-depends-on-cask-cyclic")) }
it {
is_expected.to raise_error(Hbc::CaskCyclicDependencyError,
"Cask 'with-depends-on-cask-cyclic' includes cyclic dependencies on other Casks: with-depends-on-cask-cyclic-helper")
@ -31,26 +32,31 @@ describe "Satisfy Dependencies and Requirements", :cask do
describe "depends_on macos" do
context "given an array" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-depends-on-macos-array")) }
it { is_expected.not_to raise_error }
end
context "given a comparison" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-depends-on-macos-comparison")) }
it { is_expected.not_to raise_error }
end
context "given a string" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-depends-on-macos-string")) }
it { is_expected.not_to raise_error }
end
context "given a symbol" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-depends-on-macos-symbol")) }
it { is_expected.not_to raise_error }
end
context "when not satisfied" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-depends-on-macos-failure")) }
it { is_expected.to raise_error(Hbc::CaskError) }
end
end
@ -58,12 +64,13 @@ describe "Satisfy Dependencies and Requirements", :cask do
describe "depends_on arch" do
context "when satisfied" do
let(:cask) { Hbc::CaskLoader.load(cask_path("with-depends-on-arch")) }
it { is_expected.not_to raise_error }
end
end
describe "depends_on x11" do
before(:each) do
before do
allow(MacOS::X11).to receive(:installed?).and_return(x11_installed)
end

View File

@ -93,6 +93,71 @@ describe "download strategies", :cask do
expect(curl_args.each_cons(2)).to include(["-e", "http://somehost/also"])
end
end
context "with a file name trailing the URL path" do
describe "#tarball_path" do
subject { downloader.tarball_path }
its(:extname) { is_expected.to eq(".dmg") }
end
end
context "with no discernible file name in it" do
let(:url) { "http://example.com/download" }
describe "#tarball_path" do
subject { downloader.tarball_path }
its(:to_path) { is_expected.to end_with("some-cask--1.2.3.4") }
end
end
context "with a file name trailing the first query parameter" do
let(:url) { "http://example.com/download?file=cask.zip&a=1" }
describe "#tarball_path" do
subject { downloader.tarball_path }
its(:extname) { is_expected.to eq(".zip") }
end
end
context "with a file name trailing the second query parameter" do
let(:url) { "http://example.com/dl?a=1&file=cask.zip&b=2" }
describe "#tarball_path" do
subject { downloader.tarball_path }
its(:extname) { is_expected.to eq(".zip") }
end
end
context "with an unusually long query string" do
let(:url) do
[
"https://node49152.ssl.fancycdn.example.com",
"/fancycdn/node/49152/file/upload/download",
"?cask_class=zf920df",
"&cask_group=2348779087242312",
"&cask_archive_file_name=cask.zip",
"&signature=CGmDulxL8pmutKTlCleNTUY%2FyO9Xyl5u9yVZUE0",
"uWrjadjuz67Jp7zx3H7NEOhSyOhu8nzicEHRBjr3uSoOJzwkLC8L",
"BLKnz%2B2X%2Biq5m6IdwSVFcLp2Q1Hr2kR7ETn3rF1DIq5o0lHC",
"yzMmyNe5giEKJNW8WF0KXriULhzLTWLSA3ZTLCIofAdRiiGje1kN",
"YY3C0SBqymQB8CG3ONn5kj7CIGbxrDOq5xI2ZSJdIyPysSX7SLvE",
"DBw2KdR24q9t1wfjS9LUzelf5TWk6ojj8p9%2FHjl%2Fi%2FVCXN",
"N4o1mW%2FMayy2tTY1qcC%2FTmqI1ulZS8SNuaSgr9Iys9oDF1%2",
"BPK%2B4Sg==",
].join("")
end
describe "#tarball_path" do
subject { downloader.tarball_path }
its(:extname) { is_expected.to eq(".zip") }
its("to_path.length") { is_expected.to be_between(0, 255) }
end
end
end
describe Hbc::CurlPostDownloadStrategy do
@ -142,6 +207,7 @@ describe "download strategies", :cask do
let(:url_options) { { using: :svn } }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:downloader) { Hbc::SubversionDownloadStrategy.new(cask, command: fake_system_command) }
before do
allow(fake_system_command).to receive(:run!)
end

View File

@ -1,9 +1,10 @@
describe Hbc::DSL::StanzaProxy, :cask do
subject { stanza_proxy }
let(:stanza_proxy) {
described_class.new(Array) { [:foo, :bar, :cake] }
}
subject { stanza_proxy }
it { is_expected.to be_a_proxy }
it { is_expected.to respond_to(:pop) }
its(:pop) { is_expected.to eq(:cake) }

View File

@ -3,6 +3,7 @@ describe Hbc::DSL::Version, :cask do
expectations.each do |input_value, expected_output|
context "when #{input_name} is #{input_value.inspect}" do
let(input_name.to_sym) { input_value }
it { is_expected.to eq expected_output }
end
end
@ -13,17 +14,20 @@ describe Hbc::DSL::Version, :cask do
context "when other is nil" do
let(:other) { nil }
it { is_expected.to be false }
end
context "when other is a String" do
context "when other == self.raw_version" do
let(:other) { "1.2.3" }
it { is_expected.to be true }
end
context "when other != self.raw_version" do
let(:other) { "1.2.3.4" }
it { is_expected.to be false }
end
end
@ -31,11 +35,13 @@ describe Hbc::DSL::Version, :cask do
context "when other is a #{described_class}" do
context "when other.raw_version == self.raw_version" do
let(:other) { described_class.new("1.2.3") }
it { is_expected.to be true }
end
context "when other.raw_version != self.raw_version" do
let(:other) { described_class.new("1.2.3.4") }
it { is_expected.to be false }
end
end
@ -45,16 +51,19 @@ describe Hbc::DSL::Version, :cask do
describe "#==" do
subject { version == other }
include_examples "version equality"
end
describe "#eql?" do
subject { version.eql?(other) }
include_examples "version equality"
end
shared_examples "version expectations hash" do |method, hash|
subject { version.send(method) }
include_examples "expectations hash", :raw_version,
{ :latest => "latest",
"latest" => "latest",

View File

@ -44,6 +44,7 @@ describe Hbc::DSL, :cask do
describe "header line" do
context "when invalid" do
let(:token) { "invalid/invalid-header-format" }
it "raises an error" do
expect { cask }.to raise_error(SyntaxError)
end
@ -273,6 +274,7 @@ describe Hbc::DSL, :cask do
describe "version stanza" do
let(:token) { "invalid/invalid-two-version" }
it "prevents defining multiple versions" do
expect { cask }.to raise_error(Hbc::CaskInvalidError, /'version' stanza may only appear once/)
end
@ -313,6 +315,7 @@ describe Hbc::DSL, :cask do
context "with :key_url" do
let(:token) { "with-gpg-key-url" }
it "is allowed to be specified" do
expect(cask.gpg.to_s).to match(/\S/)
end
@ -404,6 +407,7 @@ describe Hbc::DSL, :cask do
describe "depends_on cask" do
context "specifying one" do
let(:token) { "with-depends-on-cask" }
it "is allowed" do
expect(cask.depends_on.cask).not_to be nil
end

View File

@ -5,6 +5,7 @@ describe "Operations on staged Casks", :cask do
describe "bundle ID" do
let(:cask) { Hbc::CaskLoader.load(cask_path("local-transmission")) }
let(:installer) { Hbc::Installer.new(cask) }
it "fetches the bundle ID from a staged cask" do
installer.install
expect(installer.bundle_identifier).to eq("org.m0k.transmission")

View File

@ -3,6 +3,7 @@ require "hbc/system_command"
describe Hbc::SystemCommand::Result, :cask do
describe "::_parse_plist" do
subject { described_class._parse_plist(command, input) }
let(:command) { Hbc::SystemCommand.new("/usr/bin/true", {}) }
let(:plist) {
<<~EOS

View File

@ -41,12 +41,12 @@ describe Hbc::Verify, :cask do
end
describe ".all" do
subject { described_class.all(cask, downloaded_path) }
let(:downloaded_path) { double("downloaded_path") }
let(:applicable_verification) { double("applicable_verification") }
let(:inapplicable_verification) { double("inapplicable_verification") }
subject { described_class.all(cask, downloaded_path) }
before do
allow(applicable_verification_class).to receive(:new)
.and_return(applicable_verification)

View File

@ -3,6 +3,7 @@ require "caveats"
describe Caveats do
subject { described_class.new(f) }
let(:f) { formula { url "foo-1.0" } }
specify "#f" do

View File

@ -3,11 +3,13 @@ require "checksum"
describe Checksum do
describe "#empty?" do
subject { described_class.new(:sha256, "") }
it { is_expected.to be_empty }
end
describe "#==" do
subject { described_class.new(:sha256, TEST_SHA256) }
let(:other) { described_class.new(:sha256, TEST_SHA256) }
let(:other_reversed) { described_class.new(:sha256, TEST_SHA256.reverse) }
let(:other_sha1) { described_class.new(:sha1, TEST_SHA1) }
@ -15,5 +17,6 @@ describe Checksum do
it { is_expected.to eq(other) }
it { is_expected.not_to eq(other_reversed) }
it { is_expected.not_to eq(other_sha1) }
it { is_expected.not_to eq(nil) }
end
end

View File

@ -5,9 +5,10 @@ describe Cleaner do
include FileUtils
subject { described_class.new(f) }
let(:f) { formula("cleaner_test") { url "foo-1.0" } }
before(:each) do
before do
f.prefix.mkpath
end

View File

@ -5,23 +5,27 @@ require "pathname"
describe Homebrew::Cleanup do
let(:ds_store) { Pathname.new("#{HOMEBREW_PREFIX}/Library/.DS_Store") }
let(:lock_file) { Pathname.new("#{HOMEBREW_LOCK_DIR}/foo") }
let(:sec_in_a_day) { 60 * 60 * 24 }
around(:each) do |example|
around do |example|
begin
FileUtils.touch ds_store
FileUtils.touch lock_file
example.run
ensure
FileUtils.rm_f ds_store
FileUtils.rm_f lock_file
end
end
describe "::cleanup" do
it "removes .DS_Store files" do
it "removes .DS_Store and lock files" do
described_class.cleanup
expect(ds_store).not_to exist
expect(lock_file).not_to exist
end
it "doesn't remove anything if `--dry-run` is specified" do
@ -30,6 +34,15 @@ describe Homebrew::Cleanup do
described_class.cleanup
expect(ds_store).to exist
expect(lock_file).to exist
end
it "doesn't remove the lock file if it is locked" do
lock_file.open(File::RDWR | File::CREAT).flock(File::LOCK_EX | File::LOCK_NB)
described_class.cleanup
expect(lock_file).to exist
end
context "when it can't remove a keg" do
@ -37,7 +50,7 @@ describe Homebrew::Cleanup do
let(:f2) { Class.new(Testball) { version "0.2" }.new }
let(:unremovable_kegs) { [] }
before(:each) do
before do
described_class.instance_variable_set(:@unremovable_kegs, [])
[f1, f2].each do |f|
f.brew do
@ -217,7 +230,7 @@ describe Homebrew::Cleanup do
let(:bottle) { (HOMEBREW_CACHE/"testball-0.0.1.bottle.tar.gz") }
let(:testball) { (HOMEBREW_CACHE/"testball-0.0.1") }
before(:each) do
before do
FileUtils.touch(bottle)
FileUtils.touch(testball)
(HOMEBREW_CELLAR/"testball"/"0.0.1").mkpath
@ -247,6 +260,8 @@ describe Homebrew::Cleanup do
end
describe "::prune?" do
alias_matcher :be_pruned, :be_prune
before do
foo.mkpath
end
@ -255,11 +270,11 @@ describe Homebrew::Cleanup do
it "returns true when path_modified_time < days_default" do
allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - sec_in_a_day * 2)
expect(described_class.prune?(foo, days_default: "1")).to be_truthy
expect(described_class).to be_pruned(foo, days_default: "1")
end
it "returns false when path_modified_time >= days_default" do
expect(described_class.prune?(foo, days_default: "2")).to be_falsey
expect(described_class).not_to be_pruned(foo, days_default: "2")
end
end
end

View File

@ -0,0 +1,72 @@
require_relative "../cli_parser"
describe Homebrew::CLI::Parser do
describe "test switch options" do
before do
allow(ENV).to receive(:[]).with("HOMEBREW_PRY").and_return("1")
allow(ENV).to receive(:[]).with("HOMEBREW_VERBOSE")
end
subject(:parser) {
described_class.new do
switch :verbose, description: "Flag for verbosity"
switch "--more-verbose", description: "Flag for higher verbosity"
switch "--pry", env: :pry
end
}
it "parses short option" do
args = parser.parse(["-v"])
expect(args).to be_verbose
end
it "parses a single valid option" do
args = parser.parse(["--verbose"])
expect(args).to be_verbose
end
it "parses a valid option along with few unnamed args" do
args = %w[--verbose unnamed args]
parser.parse(args)
expect(args).to eq %w[unnamed args]
end
it "parses a single option and checks other options to be nil" do
args = parser.parse(["--verbose"])
expect(args).to be_verbose
expect(args.more_verbose?).to be nil
end
it "raises an exception when an invalid option is passed" do
expect { parser.parse(["--random"]) }.to raise_error(OptionParser::InvalidOption, /--random/)
end
it "maps environment var to an option" do
args = parser.parse([])
expect(args.pry?).to be true
end
end
describe "test long flag options" do
subject(:parser) {
described_class.new do
flag "--filename", description: "Name of the file", required: true
comma_array "--files", description: "Comma separated filenames"
end
}
it "parses a long flag option with its argument" do
args = parser.parse(["--filename=random.txt"])
expect(args.filename).to eq "random.txt"
end
it "raises an exception when a flag's required arg is not passed" do
expect { parser.parse(["--filename"]) }.to raise_error(OptionParser::MissingArgument, /--filename/)
end
it "parses a comma array flag option" do
args = parser.parse(["--files=random1.txt,random2.txt"])
expect(args.files).to eq %w[random1.txt random2.txt]
end
end
end

View File

@ -1,5 +1,5 @@
describe "brew analytics", :integration_test do
before(:each) do
before do
HOMEBREW_REPOSITORY.cd do
system "git", "init"
end

View File

@ -23,7 +23,7 @@ RSpec.shared_context "custom internal commands" do
]
end
around(:each) do |example|
around do |example|
begin
cmds.each do |f|
FileUtils.touch f

View File

@ -1,5 +1,5 @@
describe "brew migrate", :integration_test do
before(:each) do
before do
setup_test_formula "testball1"
setup_test_formula "testball2"
end

View File

@ -1,5 +1,5 @@
describe "brew missing", :integration_test do
before(:each) do
before do
setup_test_formula "foo"
setup_test_formula "bar"
end

View File

@ -4,7 +4,7 @@ describe "brew pin", :integration_test do
(HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath
expect { brew "pin", "testball" }.to be_a_success
expect { brew "upgrade" }.to be_a_success
expect { brew "upgrade" }.to be_a_failure
expect(HOMEBREW_CELLAR/"testball/0.1").not_to be_a_directory
end

View File

@ -1,7 +1,7 @@
require "extend/ENV"
describe "brew reinstall", :integration_test do
before(:each) do
before do
setup_test_formula "testball"
expect { brew "install", "testball", "--with-foo" }.to be_a_success

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