Merge branch 'master' into undeclared_runtime_dependencies

This commit is contained in:
Alyssa Ross 2018-03-12 09:22:39 +00:00
commit 6cd195723f
No known key found for this signature in database
GPG Key ID: 6CF064D149E3ABDB
62 changed files with 511 additions and 291 deletions

View File

@ -26,6 +26,9 @@ Layout/CaseIndentation:
Layout/EmptyLineBetweenDefs: Layout/EmptyLineBetweenDefs:
AllowAdjacentOneLineDefs: true AllowAdjacentOneLineDefs: true
Layout/EndAlignment:
EnforcedStyleAlignWith: variable
Layout/IndentArray: Layout/IndentArray:
EnforcedStyle: special_inside_parentheses EnforcedStyle: special_inside_parentheses
@ -52,9 +55,6 @@ Lint/AmbiguousBlockAssociation:
Lint/AssignmentInCondition: Lint/AssignmentInCondition:
Enabled: false Enabled: false
Lint/EndAlignment:
EnforcedStyleAlignWith: variable
# so many of these in formulae and can't be autocorrected # so many of these in formulae and can't be autocorrected
Lint/ParenthesesAsGroupedExpression: Lint/ParenthesesAsGroupedExpression:
Enabled: false Enabled: false
@ -205,7 +205,10 @@ Style/TernaryParentheses:
EnforcedStyle: require_parentheses_when_complex EnforcedStyle: require_parentheses_when_complex
# makes diffs nicer # makes diffs nicer
Style/TrailingCommaInLiteral: Style/TrailingCommaInArrayLiteral:
EnforcedStyleForMultiline: comma
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: comma EnforcedStyleForMultiline: comma
Style/TrailingCommaInArguments: Style/TrailingCommaInArguments:
@ -215,6 +218,10 @@ Style/TrailingCommaInArguments:
Naming/VariableNumber: Naming/VariableNumber:
Enabled: false Enabled: false
# doesn't make sense for Homebrew/brew but does for taps
Naming/UncommunicativeMethodParamName:
Enabled: true
Style/WordArray: Style/WordArray:
MinSize: 4 MinSize: 4

View File

@ -68,6 +68,10 @@ Naming/PredicateName:
- 'compat/**/*' - 'compat/**/*'
NameWhitelist: is_32_bit?, is_64_bit? NameWhitelist: is_32_bit?, is_64_bit?
# f meaning formulae is pretty standard
Naming/UncommunicativeMethodParamName:
Enabled: false
Style/BlockDelimiters: Style/BlockDelimiters:
Exclude: Exclude:
- '**/*_spec.rb' - '**/*_spec.rb'

View File

@ -1,3 +1,5 @@
require "uri"
module Hbc module Hbc
module CaskLoader module CaskLoader
class FromContentLoader class FromContentLoader

View File

@ -85,7 +85,7 @@ module Hbc
executable, *args = expanded_command executable, *args = expanded_command
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = raw_stdin, raw_stdout, raw_stderr, raw_wait_thr =
Open3.popen3({ "PATH" => path }, executable, *args, **options) Open3.popen3({ "PATH" => path }, [executable, executable], *args, **options)
write_input_to(raw_stdin) write_input_to(raw_stdin)
raw_stdin.close_write raw_stdin.close_write

View File

@ -25,7 +25,6 @@ class Caveats
caveats << function_completion_caveats(:zsh) caveats << function_completion_caveats(:zsh)
caveats << function_completion_caveats(:fish) caveats << function_completion_caveats(:fish)
caveats << plist_caveats caveats << plist_caveats
caveats << python_caveats
caveats << elisp_caveats caveats << elisp_caveats
caveats.compact.join("\n") caveats.compact.join("\n")
end end
@ -108,53 +107,6 @@ class Caveats
end end
end end
def python_caveats
return unless keg
return unless keg.python_site_packages_installed?
s = nil
homebrew_site_packages = Language::Python.homebrew_site_packages
user_site_packages = Language::Python.user_site_packages "python"
pth_file = user_site_packages/"homebrew.pth"
instructions = <<~EOS.gsub(/^/, " ")
mkdir -p #{user_site_packages}
echo 'import site; site.addsitedir("#{homebrew_site_packages}")' >> #{pth_file}
EOS
if f.keg_only?
keg_site_packages = f.opt_prefix/"lib/python2.7/site-packages"
unless Language::Python.in_sys_path?("python", keg_site_packages)
s = <<~EOS
If you need Python to find bindings for this keg-only formula, run:
echo #{keg_site_packages} >> #{homebrew_site_packages/f.name}.pth
EOS
s += instructions unless Language::Python.reads_brewed_pth_files?("python")
end
return s
end
return if Language::Python.reads_brewed_pth_files?("python")
if !Language::Python.in_sys_path?("python", homebrew_site_packages)
s = <<~EOS
Python modules have been installed and Homebrew's site-packages is not
in your Python sys.path, so you will not be able to import the modules
this formula installed. If you plan to develop with these modules,
please run:
EOS
s += instructions
elsif keg.python_pth_files_installed?
s = <<~EOS
This formula installed .pth files to Homebrew's site-packages and your
Python isn't configured to process them, so you will not be able to
import the modules this formula installed. If you plan to develop
with these modules, please run:
EOS
s += instructions
end
s
end
def elisp_caveats def elisp_caveats
return if f.keg_only? return if f.keg_only?
return unless keg return unless keg

View File

@ -17,7 +17,8 @@
#: #:
#: By default, `deps` shows required and recommended dependencies for #: By default, `deps` shows required and recommended dependencies for
#: <formulae>. To include the `:build` type dependencies, pass `--include-build`. #: <formulae>. To include the `:build` type dependencies, pass `--include-build`.
#: Similarly, pass `--include-optional` to include `:optional` dependencies. #: Similarly, pass `--include-optional` to include `:optional` dependencies or
#: `--include-test` to include `:test` dependencies.
#: To skip `:recommended` type dependencies, pass `--skip-recommended`. #: To skip `:recommended` type dependencies, pass `--skip-recommended`.
#: To include requirements in addition to dependencies, pass `--include-requirements`. #: To include requirements in addition to dependencies, pass `--include-requirements`.
#: #:
@ -30,8 +31,8 @@
#: If `--installed` is passed, output a tree for every installed formula. #: If `--installed` is passed, output a tree for every installed formula.
#: #:
#: The <filters> placeholder is any combination of options `--include-build`, #: The <filters> placeholder is any combination of options `--include-build`,
#: `--include-optional`, `--skip-recommended`, and `--include-requirements` as #: `--include-optional`, `--include-test`, `--skip-recommended`, and
#: documented above. #: `--include-requirements` as documented above.
#: #:
#: If `--annotate` is passed, the build, optional, and recommended dependencies #: If `--annotate` is passed, the build, optional, and recommended dependencies
#: are marked as such in the output. #: are marked as such in the output.
@ -42,7 +43,8 @@
#: dependencies of that formula. #: dependencies of that formula.
#: #:
#: The <filters> placeholder is any combination of options `--include-build`, #: The <filters> placeholder is any combination of options `--include-build`,
#: `--include-optional`, and `--skip-recommended` as documented above. #: `--include-optional`, `--include-test`, and `--skip-recommended` as
#: documented above.
# The undocumented `--for-each` option will switch into the mode used by `deps --all`, # The undocumented `--for-each` option will switch into the mode used by `deps --all`,
# but only list dependencies for specified formula, one specified formula per line. # but only list dependencies for specified formula, one specified formula per line.
@ -111,6 +113,7 @@ module Homebrew
end end
if ARGV.include?("--annotate") if ARGV.include?("--annotate")
str = "#{str} [build]" if dep.build? str = "#{str} [build]" if dep.build?
str = "#{str} [test]" if dep.test?
str = "#{str} [optional" if dep.optional? str = "#{str} [optional" if dep.optional?
str = "#{str} [recommended]" if dep.recommended? str = "#{str} [recommended]" if dep.recommended?
end end
@ -125,6 +128,11 @@ module Homebrew
else else
ignores << "build?" ignores << "build?"
end end
if ARGV.include?("--include-test")
includes << "test?"
else
ignores << "test?"
end
if ARGV.include?("--include-optional") if ARGV.include?("--include-optional")
includes << "optional?" includes << "optional?"
else else
@ -136,6 +144,9 @@ module Homebrew
deps = f.recursive_dependencies do |dependent, dep| deps = f.recursive_dependencies do |dependent, dep|
if dep.recommended? if dep.recommended?
Dependency.prune if ignores.include?("recommended?") || dependent.build.without?(dep) Dependency.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.test?
next if includes.include?("test?")
Dependency.prune
elsif dep.optional? elsif dep.optional?
Dependency.prune if !includes.include?("optional?") && !dependent.build.with?(dep) Dependency.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.build? elsif dep.build?
@ -145,6 +156,9 @@ module Homebrew
reqs = f.recursive_requirements do |dependent, req| reqs = f.recursive_requirements do |dependent, req|
if req.recommended? if req.recommended?
Requirement.prune if ignores.include?("recommended?") || dependent.build.without?(req) Requirement.prune if ignores.include?("recommended?") || dependent.build.without?(req)
elsif req.test?
next if includes.include?("test?")
Requirement.prune
elsif req.optional? elsif req.optional?
Requirement.prune if !includes.include?("optional?") && !dependent.build.with?(req) Requirement.prune if !includes.include?("optional?") && !dependent.build.with?(req)
elsif req.build? elsif req.build?
@ -191,6 +205,7 @@ module Homebrew
dependables = reqs + deps dependables = reqs + deps
dependables = dependables.reject(&:optional?) unless ARGV.include?("--include-optional") dependables = dependables.reject(&:optional?) unless ARGV.include?("--include-optional")
dependables = dependables.reject(&:build?) unless ARGV.include?("--include-build") 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 = dependables.reject(&:recommended?) if ARGV.include?("--skip-recommended")
max = dependables.length - 1 max = dependables.length - 1
@dep_stack.push f.name @dep_stack.push f.name

View File

@ -113,14 +113,14 @@ module Homebrew
url = "https://api.github.com/gists" url = "https://api.github.com/gists"
data = { "public" => true, "files" => files, "description" => description } data = { "public" => true, "files" => files, "description" => description }
scopes = GitHub::CREATE_GIST_SCOPES scopes = GitHub::CREATE_GIST_SCOPES
GitHub.open(url, data: data, scopes: scopes)["html_url"] GitHub.open_api(url, data: data, scopes: scopes)["html_url"]
end end
def create_issue(repo, title, body) def create_issue(repo, title, body)
url = "https://api.github.com/repos/#{repo}/issues" url = "https://api.github.com/repos/#{repo}/issues"
data = { "title" => title, "body" => body } data = { "title" => title, "body" => body }
scopes = GitHub::CREATE_ISSUE_SCOPES scopes = GitHub::CREATE_ISSUE_SCOPES
GitHub.open(url, data: data, scopes: scopes)["html_url"] GitHub.open_api(url, data: data, scopes: scopes)["html_url"]
end end
def gist_logs def gist_logs

View File

@ -137,7 +137,12 @@ module Homebrew
EOS EOS
end end
kegs = f.installed_kegs.sort_by(&:version) kegs = f.installed_kegs
heads, versioned = kegs.partition { |k| k.version.head? }
kegs = [
*heads.sort_by { |k| -Tab.for_keg(k).time.to_i },
*versioned.sort_by(&:version),
]
if kegs.empty? if kegs.empty?
puts "Not installed" puts "Not installed"
else else

View File

@ -344,7 +344,7 @@ module Homebrew
rescue FormulaInstallationAlreadyAttemptedError rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to install f as part of the dependency tree of # We already attempted to install f as part of the dependency tree of
# another formula. In that case, don't generate an error, just move on. # another formula. In that case, don't generate an error, just move on.
return nil
rescue CannotInstallFormulaError => e rescue CannotInstallFormulaError => e
ofail e.message ofail e.message
end end

View File

@ -47,7 +47,7 @@ module Homebrew
fi.install fi.install
fi.finish fi.finish
rescue FormulaInstallationAlreadyAttemptedError rescue FormulaInstallationAlreadyAttemptedError
return nil
rescue Exception # rubocop:disable Lint/RescueException rescue Exception # rubocop:disable Lint/RescueException
ignore_interrupts { restore_backup(keg, keg_was_linked) } ignore_interrupts { restore_backup(keg, keg_was_linked) }
raise raise

View File

@ -13,7 +13,7 @@ module Homebrew
module_function module_function
def update_preinstall_header def update_preinstall_header
@header_already_printed ||= begin @update_preinstall_header ||= begin
ohai "Auto-updated Homebrew!" if ARGV.include?("--preinstall") ohai "Auto-updated Homebrew!" if ARGV.include?("--preinstall")
true true
end end

View File

@ -10,8 +10,8 @@
#: repository's HEAD will be checked for updates when a new stable or devel #: repository's HEAD will be checked for updates when a new stable or devel
#: version has been released. #: version has been released.
#: #:
#: If <formulae> are given, upgrade only the specified brews (but do so even #: If <formulae> are given, upgrade only the specified brews (unless they
#: if they are pinned; see `pin`, `unpin`). #: are pinned; see `pin`, `unpin`).
require "cmd/install" require "cmd/install"
require "cleanup" require "cleanup"
@ -118,7 +118,7 @@ module Homebrew
fi = FormulaInstaller.new(f) fi = FormulaInstaller.new(f)
fi.options = options fi.options = options
fi.build_bottle = ARGV.build_bottle? || (!f.bottled? && f.build.build_bottle?) fi.build_bottle = ARGV.build_bottle? || (!f.bottled? && f.build.bottle?)
fi.installed_on_request = !ARGV.named.empty? fi.installed_on_request = !ARGV.named.empty?
fi.link_keg ||= keg_was_linked if keg_had_linked_opt fi.link_keg ||= keg_was_linked if keg_had_linked_opt
if tab if tab
@ -139,7 +139,7 @@ module Homebrew
rescue FormulaInstallationAlreadyAttemptedError rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to upgrade f as part of the dependency tree of # We already attempted to upgrade f as part of the dependency tree of
# another formula. In that case, don't generate an error, just move on. # another formula. In that case, don't generate an error, just move on.
return nil
rescue CannotInstallFormulaError => e rescue CannotInstallFormulaError => e
ofail e ofail e
rescue BuildError => e rescue BuildError => e

View File

@ -52,11 +52,11 @@ class DependencyCollector
output_deprecation(spec, "open-mpi") output_deprecation(spec, "open-mpi")
Dependency.new("open-mpi", tags) Dependency.new("open-mpi", tags)
when :python, :python2 when :python, :python2
output_deprecation(spec, "python@2")
Dependency.new("python@2", tags)
when :python3
output_deprecation(spec, "python") output_deprecation(spec, "python")
Dependency.new("python", tags) Dependency.new("python", tags)
when :python3
output_deprecation(spec, "python3")
Dependency.new("python3", tags)
when :emacs, :mysql, :perl, :postgresql, :rbenv, :ruby when :emacs, :mysql, :perl, :postgresql, :rbenv, :ruby
output_deprecation(spec) output_deprecation(spec)
Dependency.new(spec.to_s, tags) Dependency.new(spec.to_s, tags)

View File

@ -84,16 +84,16 @@ end
class PythonRequirement < Requirement class PythonRequirement < Requirement
fatal true fatal true
satisfy do satisfy do
odeprecated("PythonRequirement", "'depends_on \"python\"'") odeprecated("PythonRequirement", "'depends_on \"python@2\"'")
which "python" which "python2"
end end
end end
class Python3Requirement < Requirement class Python3Requirement < Requirement
fatal true fatal true
satisfy do satisfy do
odeprecated("Python3Requirement", "'depends_on \"python3\"'") odeprecated("Python3Requirement", "'depends_on \"python\"'")
which "python3" which "python"
end end
end end

View File

@ -38,9 +38,9 @@ class LanguageModuleRequirement < Requirement
when :perl when :perl
["/usr/bin/env", "perl", "-e", "use #{@import_name}"] ["/usr/bin/env", "perl", "-e", "use #{@import_name}"]
when :python when :python
["/usr/bin/env", "python", "-c", "import #{@import_name}"] ["/usr/bin/env", "python2", "-c", "import #{@import_name}"]
when :python3 when :python3
["/usr/bin/env", "python3", "-c", "import #{@import_name}"] ["/usr/bin/env", "python", "-c", "import #{@import_name}"]
when :ruby when :ruby
["/usr/bin/env", "ruby", "-rubygems", "-e", "require '#{@import_name}'"] ["/usr/bin/env", "ruby", "-rubygems", "-e", "require '#{@import_name}'"]
end end
@ -51,8 +51,8 @@ class LanguageModuleRequirement < Requirement
when :lua then "luarocks-5.2 install" when :lua then "luarocks-5.2 install"
when :lua51 then "luarocks-5.1 install" when :lua51 then "luarocks-5.1 install"
when :perl then "cpan -i" when :perl then "cpan -i"
when :python then "pip install" when :python then "pip3 install"
when :python3 then "pip3 install" when :python3 then "pip install"
when :ruby then "gem install" when :ruby then "gem install"
end end
end end

View File

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

View File

@ -1,7 +1,7 @@
require "options" require "options"
module Dependable module Dependable
RESERVED_TAGS = [:build, :optional, :recommended, :run, :linked].freeze RESERVED_TAGS = [:build, :optional, :recommended, :run, :test, :linked].freeze
def build? def build?
tags.include? :build tags.include? :build
@ -19,8 +19,12 @@ module Dependable
tags.include? :run tags.include? :run
end end
def test?
tags.include? :test
end
def required? def required?
!build? && !optional? && !recommended? !build? && !test? && !optional? && !recommended?
end end
def option_tags def option_tags

View File

@ -143,8 +143,9 @@ class Dependency
private private
def merge_tags(deps) def merge_tags(deps)
options = deps.flat_map(&:option_tags).uniq other_tags = deps.flat_map(&:option_tags).uniq
merge_necessity(deps) + merge_temporality(deps) + options other_tags << :test if deps.flat_map(&:tags).include?(:test)
merge_necessity(deps) + merge_temporality(deps) + other_tags
end end
def merge_necessity(deps) def merge_necessity(deps)

View File

@ -70,8 +70,8 @@ class DependencyCollector
Dependency.new("xz", tags) unless which("xz") Dependency.new("xz", tags) unless which("xz")
end end
def zip_dep_if_needed(tags) def unzip_dep_if_needed(tags)
Dependency.new("zip", tags) unless which("zip") Dependency.new("unzip", tags) unless which("unzip")
end end
def bzip2_dep_if_needed(tags) def bzip2_dep_if_needed(tags)
@ -166,7 +166,7 @@ class DependencyCollector
def parse_url_spec(url, tags) def parse_url_spec(url, tags)
case File.extname(url) case File.extname(url)
when ".xz" then xz_dep_if_needed(tags) when ".xz" then xz_dep_if_needed(tags)
when ".zip" then zip_dep_if_needed(tags) when ".zip" then unzip_dep_if_needed(tags)
when ".bz2" then bzip2_dep_if_needed(tags) when ".bz2" then bzip2_dep_if_needed(tags)
when ".lha", ".lzh" then Dependency.new("lha", tags) when ".lha", ".lzh" then Dependency.new("lha", tags)
when ".lz" then Dependency.new("lzip", tags) when ".lz" then Dependency.new("lzip", tags)

View File

@ -45,6 +45,18 @@ module Homebrew
next next
end end
# Don't test formulae missing test dependencies
missing_test_deps = f.recursive_dependencies do |_, dependency|
Dependency.prune if dependency.installed?
next if dependency.test?
Dependency.prune if dependency.optional?
Dependency.prune if dependency.build?
end.map(&:to_s)
unless missing_test_deps.empty?
ofail "#{f.full_name} is missing test dependencies: #{missing_test_deps.join(" ")}"
next
end
puts "Testing #{f.full_name}" puts "Testing #{f.full_name}"
env = ENV.to_hash env = ENV.to_hash

View File

@ -934,7 +934,7 @@ module Homebrew
from your PATH variable. from your PATH variable.
Python scripts will now install into #{HOMEBREW_PREFIX}/bin. Python scripts will now install into #{HOMEBREW_PREFIX}/bin.
You can delete anything, except 'Extras', from the #{HOMEBREW_PREFIX}/share/python You can delete anything, except 'Extras', from the #{HOMEBREW_PREFIX}/share/python
(and #{HOMEBREW_PREFIX}/share/python3) dir and install affected Python packages (and #{HOMEBREW_PREFIX}/share/python@2) dir and install affected Python packages
anew with `pip install --upgrade`. anew with `pip install --upgrade`.
EOS EOS
end end
@ -966,7 +966,7 @@ module Homebrew
Putting non-prefixed coreutils in your path can cause gmp builds to fail. Putting non-prefixed coreutils in your path can cause gmp builds to fail.
EOS EOS
rescue FormulaUnavailableError rescue FormulaUnavailableError
return nil
end end
def check_for_non_prefixed_findutils def check_for_non_prefixed_findutils
@ -981,7 +981,7 @@ module Homebrew
Putting non-prefixed findutils in your path can cause python builds to fail. Putting non-prefixed findutils in your path can cause python builds to fail.
EOS EOS
rescue FormulaUnavailableError rescue FormulaUnavailableError
return nil
end end
def check_for_pydistutils_cfg_in_home def check_for_pydistutils_cfg_in_home
@ -1016,24 +1016,6 @@ module Homebrew
EOS EOS
end end
def check_for_pth_support
homebrew_site_packages = Language::Python.homebrew_site_packages
return unless homebrew_site_packages.directory?
return if Language::Python.reads_brewed_pth_files?("python") != false
return unless Language::Python.in_sys_path?("python", homebrew_site_packages)
user_site_packages = Language::Python.user_site_packages "python"
<<~EOS
Your default Python does not recognize the Homebrew site-packages
directory as a special site-packages directory, which means that .pth
files will not be followed. This means you will not be able to import
some modules after installing them with Homebrew, like wxpython. To fix
this for the current user, you can run:
mkdir -p #{user_site_packages}
echo 'import site; site.addsitedir("#{homebrew_site_packages}")' >> #{user_site_packages}/homebrew.pth
EOS
end
def check_for_external_cmd_name_conflict def check_for_external_cmd_name_conflict
cmds = Tap.cmd_directories.flat_map { |p| Dir["#{p}/brew-*"] }.uniq cmds = Tap.cmd_directories.flat_map { |p| Dir["#{p}/brew-*"] }.uniq
cmds = cmds.select { |cmd| File.file?(cmd) && File.executable?(cmd) } cmds = cmds.select { |cmd| File.file?(cmd) && File.executable?(cmd) }

View File

@ -604,7 +604,7 @@ class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDo
def fetch_release_metadata def fetch_release_metadata
release_url = "https://api.github.com/repos/#{@owner}/#{@repo}/releases/tags/#{@tag}" release_url = "https://api.github.com/repos/#{@owner}/#{@repo}/releases/tags/#{@tag}"
GitHub.open(release_url) GitHub.open_api(release_url)
end end
end end

View File

@ -343,8 +343,8 @@ class FormulaAmbiguousPythonError < RuntimeError
def initialize(formula) def initialize(formula)
super <<~EOS super <<~EOS
The version of python to use with the virtualenv in the `#{formula.full_name}` formula The version of python to use with the virtualenv in the `#{formula.full_name}` formula
cannot be guessed automatically. If the simultaneous use of python and python3 cannot be guessed automatically. If the simultaneous use of python and python@2
is intentional, please add `:using => "python"` or `:using => "python3"` to is intentional, please add `:using => "python"` or `:using => "python@2"` to
`virtualenv_install_with_resources` to resolve the ambiguity manually. `virtualenv_install_with_resources` to resolve the ambiguity manually.
EOS EOS
end end

View File

@ -28,9 +28,9 @@ module EnvActivation
end end
def clear_sensitive_environment! def clear_sensitive_environment!
ENV.each_key do |key| each_key do |key|
next unless /(cookie|key|token|password)/i =~ key next unless /(cookie|key|token|password)/i =~ key
ENV.delete key delete key
end end
end end
end end

View File

@ -173,11 +173,22 @@ module Superenv
end end
def determine_library_paths def determine_library_paths
PATH.new( paths = [
keg_only_deps.map(&:opt_lib), keg_only_deps.map(&:opt_lib),
HOMEBREW_PREFIX/"lib", HOMEBREW_PREFIX/"lib",
homebrew_extra_library_paths, ]
).existing
if compiler == :llvm_clang
if MacOS::CLT.installed?
paths << "/usr/lib"
else
paths << "#{MacOS.sdk_path}/usr/lib"
end
paths << Formula["llvm"].opt_lib.to_s
end
paths += homebrew_extra_library_paths
PATH.new(paths).existing
end end
def determine_dependencies def determine_dependencies

View File

@ -31,7 +31,7 @@ class SystemConfig
return "N/A" unless CoreTap.instance.installed? return "N/A" unless CoreTap.instance.installed?
Formulary.factory(formula).linked_version || "N/A" Formulary.factory(formula).linked_version || "N/A"
rescue FormulaUnavailableError rescue FormulaUnavailableError
return "N/A" "N/A"
end end
def dump_verbose_config(out = $stdout) def dump_verbose_config(out = $stdout)

View File

@ -2219,12 +2219,12 @@ class Formula
# # `build.with?` or `build.without? "another_formula"`: # # `build.with?` or `build.without? "another_formula"`:
# depends_on "postgresql" if build.without? "sqlite" # depends_on "postgresql" if build.without? "sqlite"
# #
# <pre># Python 2.7: # <pre># Python 3.x if the `--with-python` is given to `brew install example`
# depends_on "python"</pre>
# <pre># Python 2.7 but use system Python where possible
# depends_on "python" if MacOS.version <= :snow_leopard</pre>
# <pre># Python 3.x if the `--with-python3` is given to `brew install example`
# depends_on "python3" => :optional</pre> # depends_on "python3" => :optional</pre>
# <pre># Python 2.7:
# depends_on "python@2"</pre>
# <pre># Python 2.7 but use system Python where possible
# depends_on "python@2" if MacOS.version <= :snow_leopard</pre>
def depends_on(dep) def depends_on(dep)
specs.each { |spec| spec.depends_on(dep) } specs.each { |spec| spec.depends_on(dep) }
end end

View File

@ -44,7 +44,7 @@ class FormulaVersions
# continue walking the history # continue walking the history
ohai "#{e} in #{name} at revision #{rev}", e.backtrace if ARGV.debug? ohai "#{e} in #{name} at revision #{rev}", e.backtrace if ARGV.debug?
rescue FormulaUnavailableError rescue FormulaUnavailableError
return nil
ensure ensure
Homebrew.raise_deprecation_exceptions = false Homebrew.raise_deprecation_exceptions = false
end end

View File

@ -256,7 +256,11 @@ class Keg
aliases.each do |a| aliases.each do |a|
alias_symlink = opt/a alias_symlink = opt/a
alias_symlink.delete if alias_symlink.symlink? || alias_symlink.exist? if alias_symlink.symlink? && alias_symlink.exist?
alias_symlink.delete if alias_symlink.realpath == opt_record.realpath
elsif alias_symlink.symlink? || alias_symlink.exist?
alias_symlink.delete
end
end end
Pathname.glob("#{opt_record}@*").each do |a| Pathname.glob("#{opt_record}@*").each do |a|
@ -519,6 +523,7 @@ class Keg
def delete_pyc_files! def delete_pyc_files!
find { |pn| pn.delete if %w[.pyc .pyo].include?(pn.extname) } find { |pn| pn.delete if %w[.pyc .pyo].include?(pn.extname) }
find { |pn| pn.delete if pn.basename.to_s == "__pycache__" }
end end
private private

View File

@ -9,7 +9,7 @@ module Language
Version.create(version.to_s) Version.create(version.to_s)
end end
def self.homebrew_site_packages(version = "2.7") def self.homebrew_site_packages(version = "3.6")
HOMEBREW_PREFIX/"lib/python#{version}/site-packages" HOMEBREW_PREFIX/"lib/python#{version}/site-packages"
end end
@ -89,7 +89,7 @@ module Language
# @param venv_root [Pathname, String] the path to the root of the virtualenv # @param venv_root [Pathname, String] the path to the root of the virtualenv
# (often `libexec/"venv"`) # (often `libexec/"venv"`)
# @param python [String] which interpreter to use (e.g. "python" # @param python [String] which interpreter to use (e.g. "python"
# or "python3") # or "python2")
# @param formula [Formula] the active Formula # @param formula [Formula] the active Formula
# @return [Virtualenv] a {Virtualenv} instance # @return [Virtualenv] a {Virtualenv} instance
def virtualenv_create(venv_root, python = "python", formula = self) def virtualenv_create(venv_root, python = "python", formula = self)
@ -115,8 +115,8 @@ module Language
# Returns true if a formula option for the specified python is currently # Returns true if a formula option for the specified python is currently
# active or if the specified python is required by the formula. Valid # active or if the specified python is required by the formula. Valid
# inputs are "python", "python3", :python, and :python3. Note that # inputs are "python", "python2", :python, and :python2. Note that
# "with-python", "without-python", "with-python3", and "without-python3" # "with-python", "without-python", "with-python@2", and "without-python@2"
# formula options are handled correctly even if not associated with any # formula options are handled correctly even if not associated with any
# corresponding depends_on statement. # corresponding depends_on statement.
# @api private # @api private
@ -128,16 +128,17 @@ module Language
# Helper method for the common case of installing a Python application. # Helper method for the common case of installing a Python application.
# Creates a virtualenv in `libexec`, installs all `resource`s defined # Creates a virtualenv in `libexec`, installs all `resource`s defined
# on the formula, and then installs the formula. An options hash may be # on the formula, and then installs the formula. An options hash may be
# passed (e.g., :using => "python3") to override the default, guessed # passed (e.g., :using => "python") to override the default, guessed
# formula preference for python or python3, or to resolve an ambiguous # formula preference for python or python2, or to resolve an ambiguous
# case where it's not clear whether python or python3 should be the # case where it's not clear whether python or python2 should be the
# default guess. # default guess.
def virtualenv_install_with_resources(options = {}) def virtualenv_install_with_resources(options = {})
python = options[:using] python = options[:using]
if python.nil? if python.nil?
wanted = %w[python python@2 python@3 python3].select { |py| needs_python?(py) } wanted = %w[python python@2 python2 python3 python@3].select { |py| needs_python?(py) }
raise FormulaAmbiguousPythonError, self if wanted.size > 1 raise FormulaAmbiguousPythonError, self if wanted.size > 1
python = wanted.first || "python2.7" python = wanted.first || "python2.7"
python = "python3" if python == "python"
end end
venv = virtualenv_create(libexec, python.delete("@")) venv = virtualenv_create(libexec, python.delete("@"))
venv.pip_install resources venv.pip_install resources
@ -154,7 +155,7 @@ module Language
# @param venv_root [Pathname, String] the path to the root of the # @param venv_root [Pathname, String] the path to the root of the
# virtualenv # virtualenv
# @param python [String] which interpreter to use; i.e. "python" or # @param python [String] which interpreter to use; i.e. "python" or
# "python3" # "python2"
def initialize(formula, venv_root, python) def initialize(formula, venv_root, python)
@formula = formula @formula = formula
@venv_root = Pathname.new(venv_root) @venv_root = Pathname.new(venv_root)
@ -180,11 +181,11 @@ module Language
end end
end end
# Robustify symlinks to survive python3 patch upgrades # Robustify symlinks to survive python patch upgrades
@venv_root.find do |f| @venv_root.find do |f|
next unless f.symlink? next unless f.symlink?
next unless (rp = f.realpath.to_s).start_with? HOMEBREW_CELLAR next unless (rp = f.realpath.to_s).start_with? HOMEBREW_CELLAR
python = rp.include?("python3") ? "python3" : "python" python = rp.include?("python@2") ? "python@2" : "python"
new_target = rp.sub %r{#{HOMEBREW_CELLAR}/#{python}/[^/]+}, Formula[python].opt_prefix new_target = rp.sub %r{#{HOMEBREW_CELLAR}/#{python}/[^/]+}, Formula[python].opt_prefix
f.unlink f.unlink
f.make_symlink new_target f.make_symlink new_target
@ -192,7 +193,7 @@ module Language
Pathname.glob(@venv_root/"lib/python*/orig-prefix.txt").each do |prefix_file| Pathname.glob(@venv_root/"lib/python*/orig-prefix.txt").each do |prefix_file|
prefix_path = prefix_file.read prefix_path = prefix_file.read
python = prefix_path.include?("python3") ? "python3" : "python" python = prefix_path.include?("python@2") ? "python@2" : "python"
prefix_path.sub! %r{^#{HOMEBREW_CELLAR}/#{python}/[^/]+}, Formula[python].opt_prefix prefix_path.sub! %r{^#{HOMEBREW_CELLAR}/#{python}/[^/]+}, Formula[python].opt_prefix
prefix_file.atomic_write prefix_path prefix_file.atomic_write prefix_path
end end

View File

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

View File

@ -183,7 +183,7 @@ class Migrator
end end
def migrate def migrate
oh1 "Migrating #{Formatter.identifier(oldname)} to #{Formatter.identifier(newname)}" oh1 "Processing #{Formatter.identifier(oldname)} formula rename to #{Formatter.identifier(newname)}"
lock lock
unlink_oldname unlink_oldname
unlink_newname if new_cellar.exist? unlink_newname if new_cellar.exist?
@ -193,6 +193,14 @@ class Migrator
link_oldname_opt link_oldname_opt
link_newname unless old_linked_keg.nil? link_newname unless old_linked_keg.nil?
update_tabs update_tabs
return unless formula.outdated?
opoo <<~EOS
#{Formatter.identifier(newname)} is outdated!
To avoid broken installations, as soon as possible please run:
brew upgrade
Or, if you're OK with a less reliable fix:
brew upgrade #{newname}
EOS
rescue Interrupt rescue Interrupt
ignore_interrupts { backup_oldname } ignore_interrupts { backup_oldname }
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
@ -226,7 +234,7 @@ class Migrator
end end
end end
oh1 "Moving #{Formatter.identifier(oldname)} children" oh1 "Moving #{Formatter.identifier(oldname)} versions to #{new_cellar}"
if new_cellar.exist? if new_cellar.exist?
FileUtils.mv(old_cellar.children, new_cellar) FileUtils.mv(old_cellar.children, new_cellar)
else else
@ -261,7 +269,7 @@ class Migrator
end end
def unlink_newname def unlink_newname
oh1 "Unlinking #{Formatter.identifier(newname)}" oh1 "Temporarily unlinking #{Formatter.identifier(newname)}"
new_cellar.subdirs.each do |d| new_cellar.subdirs.each do |d|
keg = Keg.new(d) keg = Keg.new(d)
keg.unlink keg.unlink
@ -269,7 +277,7 @@ class Migrator
end end
def link_newname def link_newname
oh1 "Linking #{Formatter.identifier(newname)}" oh1 "Relinking #{Formatter.identifier(newname)}"
new_keg = Keg.new(new_linked_keg_record) new_keg = Keg.new(new_linked_keg_record)
# If old_keg wasn't linked then we just optlink a keg. # If old_keg wasn't linked then we just optlink a keg.
@ -288,7 +296,8 @@ class Migrator
new_keg.remove_linked_keg_record if new_keg.linked? new_keg.remove_linked_keg_record if new_keg.linked?
begin begin
new_keg.link mode = OpenStruct.new(overwrite: true)
new_keg.link(mode)
rescue Keg::ConflictError => e rescue Keg::ConflictError => e
onoe "Error while executing `brew link` step on #{newname}" onoe "Error while executing `brew link` step on #{newname}"
puts e puts e

View File

@ -131,7 +131,7 @@ module OS
xcodebuild_output = Utils.popen_read(xcodebuild_path, "-version") xcodebuild_output = Utils.popen_read(xcodebuild_path, "-version")
next unless $CHILD_STATUS.success? next unless $CHILD_STATUS.success?
xcode_version = xcodebuild_output[/Xcode (\d(\.\d)*)/, 1] xcode_version = xcodebuild_output[/Xcode (\d+(\.\d+)*)/, 1]
return xcode_version if xcode_version return xcode_version if xcode_version
# Xcode 2.x's xcodebuild has a different version string # Xcode 2.x's xcodebuild has a different version string

View File

@ -2,6 +2,7 @@ require_relative "./rubocops/bottle_block_cop"
require_relative "./rubocops/formula_desc_cop" require_relative "./rubocops/formula_desc_cop"
require_relative "./rubocops/components_order_cop" require_relative "./rubocops/components_order_cop"
require_relative "./rubocops/components_redundancy_cop" require_relative "./rubocops/components_redundancy_cop"
require_relative "./rubocops/dependency_order_cop"
require_relative "./rubocops/homepage_cop" require_relative "./rubocops/homepage_cop"
require_relative "./rubocops/text_cop" require_relative "./rubocops/text_cop"
require_relative "./rubocops/caveats_cop" require_relative "./rubocops/caveats_cop"

View File

@ -0,0 +1,166 @@
require_relative "./extend/formula_cop"
module RuboCop
module Cop
module NewFormulaAudit
# This cop checks for correct order of `depends_on` in a Formula
#
# precedence order:
# build-time > run-time > normal > recommended > optional
class DependencyOrder < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body_node)
check_dependency_nodes_order(body_node)
[:devel, :head, :stable].each do |block_name|
block = find_block(body_node, block_name)
next unless block
check_dependency_nodes_order(block.body)
end
end
def check_dependency_nodes_order(parent_node)
return if parent_node.nil?
dependency_nodes = fetch_depends_on_nodes(parent_node)
ordered = dependency_nodes.sort { |a, b| sort_by_dependency_name(a, b) }
ordered = sort_dependencies_by_type(ordered)
sort_conditional_dependencies!(ordered)
verify_order_in_source(ordered)
end
# Match all `depends_on` nodes among childnodes of given parent node
def fetch_depends_on_nodes(parent_node)
parent_node.each_child_node.select { |x| depends_on_node?(x) }
end
def sort_by_dependency_name(a, b)
a_name = dependency_name(a)
b_name = dependency_name(b)
if a_name < b_name
-1
elsif a_name > b_name
1
else
0
end
end
# Separate dependencies according to precedence order:
# build-time > run-time > normal > recommended > optional
def sort_dependencies_by_type(dependency_nodes)
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)
end
# `depends_on :apple if build.with? "foo"` should always be defined
# after `depends_on :foo`
# This method reorders dependencies array according to above rule
def sort_conditional_dependencies!(ordered)
length = ordered.size
idx = 0
while idx < length
idx1, idx2 = nil
ordered.each_with_index do |dep, pos|
idx = pos+1
match_nodes = build_with_dependency_name(dep)
idx1 = pos if match_nodes && !match_nodes.empty?
next unless idx1
idx2 = nil
ordered.drop(idx1+1).each_with_index do |dep2, pos2|
next unless match_nodes.index(dependency_name(dep2))
idx2 = pos2 if idx2.nil? || pos2 > idx2
end
break if idx2
end
insert_after!(ordered, idx1, idx2+idx1) if idx2
end
ordered
end
# Verify actual order of sorted `depends_on` nodes in source code
# Else raise RuboCop problem
def verify_order_in_source(ordered)
ordered.each_with_index do |dependency_node_1, idx|
l1 = line_number(dependency_node_1)
dependency_node_2 = nil
ordered.drop(idx+1).each do |node2|
l2 = line_number(node2)
dependency_node_2 = node2 if l2 < l1
end
next unless dependency_node_2
@offensive_nodes = [dependency_node_1, dependency_node_2]
component_problem dependency_node_1, dependency_node_2
end
end
# Node pattern method to match
# `depends_on` variants
def_node_matcher :depends_on_node?, <<~EOS
{(if _ (send nil? :depends_on ...) nil?)
(send nil? :depends_on ...)}
EOS
def_node_search :buildtime_dependency?, "(sym :build)"
def_node_search :recommended_dependency?, "(sym :recommended)"
def_node_search :runtime_dependency?, "(sym :run)"
def_node_search :optional_dependency?, "(sym :optional)"
def_node_search :negate_normal_dependency?, "(sym {:build :recommended :run :optional})"
# Node pattern method to extract `name` in `depends_on :name`
def_node_search :dependency_name_node, <<~EOS
{(send nil? :depends_on {(hash (pair $_ _)) $({str sym} _)})
(if _ (send nil? :depends_on {(hash (pair $_ _)) $({str sym} _)}) nil?)}
EOS
# Node pattern method to extract `name` in `build.with? :name`
def_node_search :build_with_dependency_node, <<~EOS
(send (send nil? :build) :with? $({str sym} _))
EOS
def insert_after!(arr, idx1, idx2)
arr.insert(idx2+1, arr.delete_at(idx1))
end
def build_with_dependency_name(node)
match_nodes = build_with_dependency_node(node)
match_nodes = match_nodes.to_a.delete_if(&:nil?)
match_nodes.map { |n| string_content(n) } unless match_nodes.empty?
end
def dependency_name(dependency_node)
match_node = dependency_name_node(dependency_node).to_a.first
string_content(match_node) if match_node
end
def autocorrect(_node)
succeeding_node = @offensive_nodes[0]
preceding_node = @offensive_nodes[1]
lambda do |corrector|
reorder_components(corrector, succeeding_node, preceding_node)
end
end
private
def component_problem(c1, c2)
offending_node(c1)
problem "dependency \"#{dependency_name(c1)}\" (line #{line_number(c1)}) should be put before dependency \"#{dependency_name(c2)}\" (line #{line_number(c2)})"
end
# Reorder two nodes in the source, using the corrector instance in autocorrect method
def reorder_components(corrector, node1, node2)
indentation = " " * (start_column(node2) - line_start_column(node2))
line_breaks = "\n"
corrector.insert_before(node2.source_range, node1.source + line_breaks + indentation)
corrector.remove(range_with_surrounding_space(range: node1.source_range, side: :left))
end
end
end
end
end

View File

@ -4,6 +4,8 @@ require_relative "../../extend/string"
module RuboCop module RuboCop
module Cop module Cop
class FormulaCop < Cop class FormulaCop < Cop
include RangeHelp
attr_accessor :file_path attr_accessor :file_path
@registry = Cop.registry @registry = Cop.registry

View File

@ -108,10 +108,10 @@ class Sandbox
unless logs.empty? unless logs.empty?
if @logfile if @logfile
log = open(@logfile, "w") File.open(@logfile, "w") do |log|
log.write logs log.write logs
log.write "\nWe use time to filter sandbox log. Therefore, unrelated logs may be recorded.\n" log.write "\nWe use time to filter sandbox log. Therefore, unrelated logs may be recorded.\n"
log.close end
end end
if @failed && ARGV.verbose? if @failed && ARGV.verbose?

View File

@ -326,8 +326,8 @@ class Tab < OpenStruct
"time" => time, "time" => time,
"source_modified_time" => source_modified_time.to_i, "source_modified_time" => source_modified_time.to_i,
"HEAD" => self.HEAD, "HEAD" => self.HEAD,
"stdlib" => (stdlib.to_s if stdlib), "stdlib" => (stdlib&.to_s),
"compiler" => (compiler.to_s if compiler), "compiler" => (compiler&.to_s),
"aliases" => aliases, "aliases" => aliases,
"runtime_dependencies" => runtime_dependencies, "runtime_dependencies" => runtime_dependencies,
"source" => source, "source" => source,

View File

@ -141,6 +141,20 @@ shared_examples EnvActivation do
expect(subject["MAKEFLAGS"]).to eq("-j4") expect(subject["MAKEFLAGS"]).to eq("-j4")
end end
describe "#clear_sensitive_environment!" do
it "removes sensitive environment variables" do
subject["SECRET_TOKEN"] = "password"
subject.clear_sensitive_environment!
expect(subject).not_to include("SECRET_TOKEN")
end
it "leaves non-sensitive environment variables alone" do
subject["FOO"] = "bar"
subject.clear_sensitive_environment!
expect(subject["FOO"]).to eq "bar"
end
end
end end
describe Stdenv do describe Stdenv do

View File

@ -1,7 +1,7 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
ast (2.3.0) ast (2.4.0)
codecov (0.1.10) codecov (0.1.10)
json json
simplecov simplecov
@ -9,36 +9,36 @@ GEM
diff-lcs (1.3) diff-lcs (1.3)
docile (1.1.5) docile (1.1.5)
json (2.1.0) json (2.1.0)
parallel (1.12.0) parallel (1.12.1)
parallel_tests (2.17.0) parallel_tests (2.21.2)
parallel parallel
parser (2.4.0.2) parser (2.5.0.2)
ast (~> 2.3) ast (~> 2.4.0)
powerpack (0.1.1) powerpack (0.1.1)
rainbow (3.0.0) rainbow (3.0.0)
rspec (3.6.0) rspec (3.7.0)
rspec-core (~> 3.6.0) rspec-core (~> 3.7.0)
rspec-expectations (~> 3.6.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.7.0)
rspec-core (3.6.0) rspec-core (3.7.1)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-expectations (3.6.0) rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-its (1.2.0) rspec-its (1.2.0)
rspec-core (>= 3.0.0) rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0) rspec-expectations (>= 3.0.0)
rspec-mocks (3.6.0) rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-retry (0.5.6) rspec-retry (0.5.6)
rspec-core (> 3.3, < 3.8) rspec-core (> 3.3, < 3.8)
rspec-support (3.6.0) rspec-support (3.7.1)
rspec-wait (0.0.9) rspec-wait (0.0.9)
rspec (>= 3, < 4) rspec (>= 3, < 4)
rubocop (0.52.1) rubocop (0.53.0)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.4.0.2, < 3.0) parser (>= 2.5)
powerpack (~> 0.1) powerpack (~> 0.1)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
@ -62,7 +62,7 @@ DEPENDENCIES
rspec-its rspec-its
rspec-retry rspec-retry
rspec-wait rspec-wait
rubocop (= 0.52.1) rubocop (= 0.53.0)
simplecov simplecov
BUNDLED WITH BUNDLED WITH

View File

@ -201,45 +201,5 @@ describe Caveats do
expect(caveats).to include(HOMEBREW_PREFIX/"share/fish/vendor_completions.d") expect(caveats).to include(HOMEBREW_PREFIX/"share/fish/vendor_completions.d")
end end
end end
context "python caveats" do
before do
(f.prefix.resolved_path/"lib/python2.7/site-packages").mkpath
end
context "when f is not keg_only" do
let(:f) {
formula do
url "foo-1.0"
end
}
let(:caveats) { described_class.new(f).caveats }
let(:user_site_packages) { Language::Python.user_site_packages("python") }
it "give commands to run when Homebrew's site-packages is not in Python sys.path" do
expect(caveats).to include("Homebrew's site-packages is not\nin your Python sys.path")
expect(caveats).to include(user_site_packages)
expect(caveats).to include("import site")
end
it "gives commands to run when python pth files are installed" do
allow(Homebrew).to receive(:_system).and_return(true)
allow(Dir).to receive(:[]).with(any_args).and_return(["blah.pth"])
expect(caveats).to include(".pth files to Homebrew's site-packages and your\nPython isn't configured")
expect(caveats).to include(user_site_packages)
expect(caveats).to include("import site")
end
end
it "gives commands to run when formula is keg_only" do
f = formula do
url "foo-1.0"
keg_only "some reason"
end
caveats = described_class.new(f).caveats
homebrew_site_packages = Language::Python.homebrew_site_packages
expect(caveats).to include("echo #{f.opt_prefix}/lib/python2.7/site-packages >> #{homebrew_site_packages/f.name}.pth")
end
end
end end
end end

View File

@ -29,7 +29,7 @@ describe "brew migrate", :integration_test do
install_and_rename_coretap_formula "testball1", "testball2" install_and_rename_coretap_formula "testball1", "testball2"
expect { brew "migrate", "testball1" } expect { brew "migrate", "testball1" }
.to output(/Migrating testball1 to testball2/).to_stdout .to output(/Processing testball1 formula rename to testball2/).to_stdout
.and not_to_output.to_stderr .and not_to_output.to_stderr
.and be_a_success .and be_a_success
end end

View File

@ -16,7 +16,7 @@ describe Homebrew do
], ],
} }
allow(GitHub).to receive(:open).and_yield(json_response) allow(GitHub).to receive(:open_api).and_yield(json_response)
expect(described_class.search_taps("some-formula")) expect(described_class.search_taps("some-formula"))
.to match(["homebrew/foo/some-formula"]) .to match(["homebrew/foo/some-formula"])

View File

@ -116,7 +116,7 @@ describe GitHubPrivateRepositoryReleaseDownloadStrategy do
describe "#fetch_release_metadata" do describe "#fetch_release_metadata" do
it "fetches release metadata from GitHub" do it "fetches release metadata from GitHub" do
expected_release_url = "https://api.github.com/repos/owner/repo/releases/tags/tag" expected_release_url = "https://api.github.com/repos/owner/repo/releases/tags/tag"
expect(GitHub).to receive(:open).with(expected_release_url).and_return({}) expect(GitHub).to receive(:open_api).with(expected_release_url).and_return({})
subject.send(:fetch_release_metadata) subject.send(:fetch_release_metadata)
end end
end end

View File

@ -31,10 +31,6 @@ describe LanguageModuleRequirement, :needs_compat do
it "does not satisfy invalid dependencies" do it "does not satisfy invalid dependencies" do
expect(described_class.new(:python, "notapackage")).not_to be_satisfied expect(described_class.new(:python, "notapackage")).not_to be_satisfied
end end
it "satisfies valid dependencies" do
expect(described_class.new(:python, "datetime")).to be_satisfied
end
end end
context "when the language is Ruby" do context "when the language is Ruby" do

View File

@ -10,7 +10,7 @@ describe DependencyCollector do
describe "#add" do describe "#add" do
resource = Resource.new resource = Resource.new
context "when xz, zip, and bzip2 are not available" do context "when xz, unzip, and bzip2 are not available" do
it "creates a resource dependency from a '.xz' URL" do it "creates a resource dependency from a '.xz' URL" do
resource.url("http://example.com/foo.xz") resource.url("http://example.com/foo.xz")
allow_any_instance_of(Object).to receive(:which).with("xz") allow_any_instance_of(Object).to receive(:which).with("xz")
@ -19,8 +19,8 @@ describe DependencyCollector do
it "creates a resource dependency from a '.zip' URL" do it "creates a resource dependency from a '.zip' URL" do
resource.url("http://example.com/foo.zip") resource.url("http://example.com/foo.zip")
allow_any_instance_of(Object).to receive(:which).with("zip") allow_any_instance_of(Object).to receive(:which).with("unzip")
expect(subject.add(resource)).to eq(Dependency.new("zip", [:build])) expect(subject.add(resource)).to eq(Dependency.new("unzip", [:build]))
end end
it "creates a resource dependency from a '.bz2' URL" do it "creates a resource dependency from a '.bz2' URL" do
@ -39,7 +39,7 @@ describe DependencyCollector do
it "does not create a resource dependency from a '.zip' URL" do it "does not create a resource dependency from a '.zip' URL" do
resource.url("http://example.com/foo.zip") resource.url("http://example.com/foo.zip")
allow_any_instance_of(Object).to receive(:which).with("zip").and_return(Pathname.new("foo")) allow_any_instance_of(Object).to receive(:which).with("unzip").and_return(Pathname.new("foo"))
expect(subject.add(resource)).to be nil expect(subject.add(resource)).to be nil
end end

View File

@ -0,0 +1,75 @@
require_relative "../../rubocops/dependency_order_cop"
describe RuboCop::Cop::NewFormulaAudit::DependencyOrder do
subject(:cop) { described_class.new }
context "depends_on" do
it "wrong conditional depends_on order" do
expect_offense(<<~RUBY)
class Foo < Formula
homepage "http://example.com"
url "http://example.com/foo-1.0.tgz"
depends_on "apple" if build.with? "foo"
depends_on "foo" => :optional
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dependency "foo" (line 5) should be put before dependency "apple" (line 4)
end
RUBY
end
it "wrong alphabetical depends_on order" do
expect_offense(<<~RUBY)
class Foo < Formula
homepage "http://example.com"
url "http://example.com/foo-1.0.tgz"
depends_on "foo"
depends_on "bar"
^^^^^^^^^^^^^^^^ dependency "bar" (line 5) should be put before dependency "foo" (line 4)
end
RUBY
end
it "wrong conditional depends_on order" do
expect_offense(<<~RUBY)
class Foo < Formula
homepage "http://example.com"
url "http://example.com/foo-1.0.tgz"
head do
depends_on "apple" if build.with? "foo"
depends_on "bar"
^^^^^^^^^^^^^^^^ dependency "bar" (line 6) should be put before dependency "apple" (line 5)
depends_on "foo" => :optional
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dependency "foo" (line 7) should be put before dependency "apple" (line 5)
end
depends_on "apple" if build.with? "foo"
depends_on "foo" => :optional
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dependency "foo" (line 10) should be put before dependency "apple" (line 9)
end
RUBY
end
end
context "autocorrect" do
it "wrong conditional depends_on order" do
source = <<~EOS
class Foo < Formula
homepage "http://example.com"
url "http://example.com/foo-1.0.tgz"
depends_on "apple" if build.with? "foo"
depends_on "foo" => :optional
end
EOS
correct_source = <<~EOS
class Foo < Formula
homepage "http://example.com"
url "http://example.com/foo-1.0.tgz"
depends_on "foo" => :optional
depends_on "apple" if build.with? "foo"
end
EOS
corrected_source = autocorrect_source(source)
expect(corrected_source).to eq(correct_source)
end
end
end

View File

@ -16,9 +16,9 @@ TEST_TMPDIR = ENV.fetch("HOMEBREW_TEST_TMPDIR") do |k|
end end
# Paths pointing into the Homebrew code base that persist across test runs # Paths pointing into the Homebrew code base that persist across test runs
HOMEBREW_LIBRARY_PATH = Pathname.new(File.expand_path("../../../..", __FILE__)) HOMEBREW_LIBRARY_PATH = Pathname.new(File.expand_path("../../..", __dir__))
HOMEBREW_SHIMS_PATH = HOMEBREW_LIBRARY_PATH.parent+"Homebrew/shims" HOMEBREW_SHIMS_PATH = HOMEBREW_LIBRARY_PATH.parent+"Homebrew/shims"
HOMEBREW_LOAD_PATH = [File.expand_path("..", __FILE__), HOMEBREW_LIBRARY_PATH].join(":") HOMEBREW_LOAD_PATH = [File.expand_path(__dir__), HOMEBREW_LIBRARY_PATH].join(":")
# Paths redirected to a temporary directory and wiped at the end of the test run # Paths redirected to a temporary directory and wiped at the end of the test run
HOMEBREW_PREFIX = Pathname.new(TEST_TMPDIR).join("prefix") HOMEBREW_PREFIX = Pathname.new(TEST_TMPDIR).join("prefix")

View File

@ -3,9 +3,9 @@ require "formula_installer"
describe Utils::Analytics do describe Utils::Analytics do
describe "::os_prefix_ci" do describe "::os_prefix_ci" do
context "when anonymous_os_prefix_ci is not set" do context "when os_prefix_ci is not set" do
before(:each) do before(:each) do
described_class.clear_anonymous_os_prefix_ci_cache described_class.clear_os_prefix_ci
end end
it "returns OS_VERSION and prefix when HOMEBREW_PREFIX is not /usr/local" do it "returns OS_VERSION and prefix when HOMEBREW_PREFIX is not /usr/local" do

View File

@ -109,7 +109,9 @@ def odeprecated(method, replacement = nil, disable: false, disable_on: nil, call
if ARGV.homebrew_developer? || disable || if ARGV.homebrew_developer? || disable ||
Homebrew.raise_deprecation_exceptions? Homebrew.raise_deprecation_exceptions?
if replacement || tap_message
developer_message = message + "Or, even better, submit a PR to fix it!" developer_message = message + "Or, even better, submit a PR to fix it!"
end
raise MethodDeprecatedError, developer_message raise MethodDeprecatedError, developer_message
elsif !Homebrew.auditing? elsif !Homebrew.auditing?
opoo "#{message}\n" opoo "#{message}\n"

View File

@ -3,13 +3,13 @@ require "erb"
module Utils module Utils
module Analytics module Analytics
class << self class << self
def clear_anonymous_os_prefix_ci_cache def clear_os_prefix_ci
return unless instance_variable_defined?(:@anonymous_os_prefix_ci) return unless instance_variable_defined?(:@os_prefix_ci)
remove_instance_variable(:@anonymous_os_prefix_ci) remove_instance_variable(:@os_prefix_ci)
end end
def os_prefix_ci def os_prefix_ci
@anonymous_os_prefix_ci ||= begin @os_prefix_ci ||= begin
os = OS_VERSION os = OS_VERSION
prefix = ", non-/usr/local" if HOMEBREW_PREFIX.to_s != "/usr/local" prefix = ", non-/usr/local" if HOMEBREW_PREFIX.to_s != "/usr/local"
ci = ", CI" if ENV["CI"] ci = ", CI" if ENV["CI"]

View File

@ -5,7 +5,7 @@ module Utils
class Bottles class Bottles
class << self class << self
def tag def tag
@bottle_tag ||= "#{ENV["HOMEBREW_PROCESSOR"]}_#{ENV["HOMEBREW_SYSTEM"]}".downcase.to_sym @tag ||= "#{ENV["HOMEBREW_PROCESSOR"]}_#{ENV["HOMEBREW_SYSTEM"]}".downcase.to_sym
end end
def built_as?(f) def built_as?(f)

View File

@ -27,7 +27,7 @@ end
module Utils module Utils
def self.git_available? def self.git_available?
@git ||= quiet_system HOMEBREW_SHIMS_PATH/"scm/git", "--version" @git_available ||= quiet_system HOMEBREW_SHIMS_PATH/"scm/git", "--version"
end end
def self.git_path def self.git_path
@ -61,7 +61,7 @@ module Utils
end end
def self.clear_git_available_cache def self.clear_git_available_cache
@git = nil @git_available = nil
@git_path = nil @git_path = nil
@git_version = nil @git_version = nil
end end

View File

@ -94,7 +94,7 @@ module GitHub
def api_credentials_error_message(response_headers, needed_scopes) def api_credentials_error_message(response_headers, needed_scopes)
return if response_headers.empty? return if response_headers.empty?
@api_credentials_error_message_printed ||= begin @api_credentials_error_message ||= begin
unauthorized = (response_headers["http/1.1"] == "401 Unauthorized") unauthorized = (response_headers["http/1.1"] == "401 Unauthorized")
scopes = response_headers["x-accepted-oauth-scopes"].to_s.split(", ") scopes = response_headers["x-accepted-oauth-scopes"].to_s.split(", ")
needed_human_scopes = needed_scopes.join(", ") needed_human_scopes = needed_scopes.join(", ")
@ -125,7 +125,7 @@ module GitHub
end end
end end
def open(url, data: nil, scopes: [].freeze) def open_api(url, data: nil, scopes: [].freeze)
# This is a no-op if the user is opting out of using the GitHub API. # This is a no-op if the user is opting out of using the GitHub API.
return block_given? ? yield({}) : {} if ENV["HOMEBREW_NO_GITHUB_API"] return block_given? ? yield({}) : {} if ENV["HOMEBREW_NO_GITHUB_API"]
@ -226,7 +226,7 @@ module GitHub
end end
def repository(user, repo) def repository(user, repo)
open(url_to("repos", user, repo)) open_api(url_to("repos", user, repo))
end end
def search_code(**qualifiers) def search_code(**qualifiers)
@ -255,7 +255,7 @@ module GitHub
def private_repo?(full_name) def private_repo?(full_name)
uri = url_to "repos", full_name uri = url_to "repos", full_name
open(uri) { |json| json["private"] } open_api(uri) { |json| json["private"] }
end end
def query_string(*main_params, **qualifiers) def query_string(*main_params, **qualifiers)
@ -275,6 +275,6 @@ module GitHub
def search(entity, *queries, **qualifiers) def search(entity, *queries, **qualifiers)
uri = url_to "search", entity uri = url_to "search", entity
uri.query = query_string(*queries, **qualifiers) uri.query = query_string(*queries, **qualifiers)
open(uri) { |json| json.fetch("items", []) } open_api(uri) { |json| json.fetch("items", []) }
end end
end end

View File

@ -66,9 +66,9 @@ then
FILTERED_ENV=() FILTERED_ENV=()
# Filter all but the specific variables. # Filter all but the specific variables.
for VAR in HOME SHELL PATH TERM LOGNAME USER CI TRAVIS TRAVIS_SUDO SSH_AUTH_SOCK SUDO_ASKPASS \ for VAR in HOME SHELL PATH TERM LOGNAME USER CI TRAVIS SSH_AUTH_SOCK SUDO_ASKPASS \
http_proxy https_proxy ftp_proxy no_proxy all_proxy HTTPS_PROXY FTP_PROXY ALL_PROXY \ http_proxy https_proxy ftp_proxy no_proxy all_proxy HTTPS_PROXY FTP_PROXY ALL_PROXY \
"${!HOMEBREW_@}" "${!HOMEBREW_@}" "${!TRAVIS_@}"
do do
# Skip if variable value is empty. # Skip if variable value is empty.
[[ -z "${!VAR}" ]] && continue [[ -z "${!VAR}" ]] && continue

View File

@ -38,15 +38,6 @@ tarballs should include the version in the filename whenever possible.
We dont accept software without a tagged version because they regularly break We dont accept software without a tagged version because they regularly break
due to upstream changes and we cant provide [bottles](Bottles.md) for them. due to upstream changes and we cant provide [bottles](Bottles.md) for them.
### Bindings
First check that there is not already a binding available via
[`gem`](https://rubygems.org/) or [`pip`](http://www.pip-installer.org/)
etc.
If not, then put bindings in the formula they bind to. This is more
useful to people. Just install the stuff! Having to faff around with
foo-ruby, foo-perl etc. is a bad user experience.
### Niche (or self-submitted) stuff ### Niche (or self-submitted) stuff
The software in question must: The software in question must:

View File

@ -11,8 +11,8 @@ Starting with OS X Lion (10.7), you need `sudo` to install to these like
so: `sudo gem install`, `sudo easy_install` or `sudo cpan -i`. so: `sudo gem install`, `sudo easy_install` or `sudo cpan -i`.
An option to avoid sudo is to use an access control list: An option to avoid sudo is to use an access control list:
`chmod +a 'user:YOUR_NAME_HERE allow add_subdirectory,add_file,delete_child,directory_inherit' /Library/Python/2.7/site-packages`, `chmod +a 'user:YOUR_NAME_HERE allow add_subdirectory,add_file,delete_child,directory_inherit' /Library/Python/3.6/site-packages`,
for example, will let you add packages to Python 2.7 as yourself. That for example, will let you add packages to Python 3.6 as yourself. That
is probably safer than changing the group ownership of the directory. is probably safer than changing the group ownership of the directory.
### So why was I using sudo? ### So why was I using sudo?
@ -29,14 +29,14 @@ Rather than changing the rights on `/Library/Python`, we recommend the
following options: following options:
### With a brewed Python ### With a brewed Python
Note, `easy_install` is deprecated. We install `pip` (or `pip3` for Note, `easy_install` is deprecated. We install `pip` (or `pip2` for
Python 3) along with python/python3. Python 2) along with python/python2.
We set up distutils such that `pip install` will always put modules in We set up distutils such that `pip install` will always put modules in
`$(brew --prefix)/lib/pythonX.Y/site-packages` and scripts in `$(brew --prefix)/lib/pythonX.Y/site-packages` and scripts in
`$(brew --prefix)/share/python`. Therefore, you wont need sudo! `$(brew --prefix)/share/python`. Therefore, you wont need sudo!
Do `brew info python` or `brew info python3` for precise information Do `brew info python` or `brew info python@2` for precise information
about the paths. Note, a brewed Python still searches for modules in about the paths. Note, a brewed Python still searches for modules in
`/Library/Python/X.Y/site-packages` and also in `/Library/Python/X.Y/site-packages` and also in
`~/Library/Python/X.Y/lib/python/site-packages`. `~/Library/Python/X.Y/lib/python/site-packages`.

View File

@ -4,33 +4,35 @@ This page describes how Python is handled in Homebrew for users. See [Python for
Homebrew should work with any [CPython](https://stackoverflow.com/questions/2324208/is-there-any-difference-between-cpython-and-python) and defaults to the macOS system Python. Homebrew should work with any [CPython](https://stackoverflow.com/questions/2324208/is-there-any-difference-between-cpython-and-python) and defaults to the macOS system Python.
Homebrew provides formulae to brew a more up-to-date Python 2.7.x and 3.x. Homebrew provides formulae to brew 3.x and a more up-to-date Python 2.7.x.
**Important:** If you choose to install a Python which isn't either of these two (system Python or brewed Python), the Homebrew team can only provide limited support. **Important:** If you choose to install a Python which isn't either of these two (system Python or brewed Python), the Homebrew team cannot support any breakage that may occur.
## Python 2.x or Python 3.x ## Python 3.x or Python 2.x
Homebrew provides one formula for Python 2.7.x and another for Python 3.x. The executables are organized as follows so that Python 2 and Python 3 can both be installed without conflict: Homebrew provides one formula for Python 3.x (`python`) and another for Python 2.7.x (`python@2`).
* `python` points to the macOS system Python (with no manual PATH modification)
* `python2` points to Homebrew's Python 2.7.x (if installed) The executables are organized as follows so that Python 2 and Python 3 can both be installed without conflict:
* `python3` points to Homebrew's Python 3.x (if installed) * `python3` points to Homebrew's Python 3.x (if installed)
* `pip2` points to Homebrew's Python 2.7.x's pip (if installed) * `python2` points to Homebrew's Python 2.7.x (if installed)
* `python` points to Homebrew's Python 2.7.x (if installed) otherwise the macOS system Python. Check out `brew info python` if you wish to add Homebrew's 3.x `python` to your `PATH`.
* `pip3` points to Homebrew's Python 3.x's pip (if installed) * `pip3` points to Homebrew's Python 3.x's pip (if installed)
* `pip` and `pip2` point to Homebrew's Python 2.7.x's pip (if installed)
([Wondering which one to choose?](https://wiki.python.org/moin/Python2orPython3)) ([Wondering which one to choose?](https://wiki.python.org/moin/Python2orPython3))
## Setuptools, Pip, etc. ## Setuptools, Pip, etc.
The Python formulae install [pip](http://www.pip-installer.org) (as `pip2` or `pip3`) and [Setuptools](https://pypi.python.org/pypi/setuptools). The Python formulae install [pip](http://www.pip-installer.org) (as `pip` or `pip2`) and [Setuptools](https://pypi.python.org/pypi/setuptools).
Setuptools can be updated via pip, without having to re-brew Python: Setuptools can be updated via pip, without having to re-brew Python:
```sh ```sh
python2 -m pip install --upgrade setuptools python -m pip install --upgrade setuptools
``` ```
Similarly, pip can be used to upgrade itself via: Similarly, pip can be used to upgrade itself via:
```sh ```sh
python2 -m pip install --upgrade pip python -m pip install --upgrade pip
``` ```
### Note on `pip install --user` ### Note on `pip install --user`
@ -39,7 +41,7 @@ The normal `pip install --user` is disabled for brewed Python. This is because o
A possible workaround (which puts executable scripts in `~/Library/Python/<X>.<Y>/bin`) is: A possible workaround (which puts executable scripts in `~/Library/Python/<X>.<Y>/bin`) is:
```sh ```sh
python2 -m pip install --user --install-option="--prefix=" <package-name> python -m pip install --user --install-option="--prefix=" <package-name>
``` ```
## `site-packages` and the `PYTHONPATH` ## `site-packages` and the `PYTHONPATH`
@ -49,12 +51,12 @@ The `site-packages` is a directory that contains Python modules (especially bind
$(brew --prefix)/lib/pythonX.Y/site-packages $(brew --prefix)/lib/pythonX.Y/site-packages
``` ```
So, for Python 2.7.x, you'll find it at `/usr/local/lib/python2.7/site-packages`. So, for Python 3.6.x, you'll find it at `/usr/local/lib/python3.6/site-packages`.
Python 2.7 also searches for modules in: Python 3.6 also searches for modules in:
- `/Library/Python/2.7/site-packages` - `/Library/Python/3.6/site-packages`
- `~/Library/Python/2.7/lib/python/site-packages` - `~/Library/Python/3.6/lib/python/site-packages`
Homebrew's `site-packages` directory is first created if (1) any Homebrew formula with Python bindings are installed, or (2) upon `brew install python`. Homebrew's `site-packages` directory is first created if (1) any Homebrew formula with Python bindings are installed, or (2) upon `brew install python`.
@ -62,9 +64,7 @@ Homebrew's `site-packages` directory is first created if (1) any Homebrew formul
The reasoning for this location is to preserve your modules between (minor) upgrades or re-installations of Python. Additionally, Homebrew has a strict policy never to write stuff outside of the `brew --prefix`, so we don't spam your system. The reasoning for this location is to preserve your modules between (minor) upgrades or re-installations of Python. Additionally, Homebrew has a strict policy never to write stuff outside of the `brew --prefix`, so we don't spam your system.
## Homebrew-provided Python bindings ## Homebrew-provided Python bindings
Some formulae provide Python bindings. Sometimes a `--with-python` or `--with-python3` option has to be passed to `brew install` in order to build the Python bindings. (Check with `brew options <formula>`.) Some formulae provide Python bindings. Sometimes a `--with-python` or `--with-python@2` option has to be passed to `brew install` in order to build the Python bindings. (Check with `brew options <formula>`.)
Homebrew builds bindings against the first `python` (and `python-config`) in your `PATH`. (Check with `which python`).
**Warning!** Python may crash (see [Common Issues](Common-Issues.md)) if you `import <module>` from a brewed Python if you ran `brew install <formula_with_python_bindings>` against the system Python. If you decide to switch to the brewed Python, then reinstall all formulae with Python bindings (e.g. `pyside`, `wxwidgets`, `pygtk`, `pygobject`, `opencv`, `vtk` and `boost-python`). **Warning!** Python may crash (see [Common Issues](Common-Issues.md)) if you `import <module>` from a brewed Python if you ran `brew install <formula_with_python_bindings>` against the system Python. If you decide to switch to the brewed Python, then reinstall all formulae with Python bindings (e.g. `pyside`, `wxwidgets`, `pygtk`, `pygobject`, `opencv`, `vtk` and `boost-python`).
@ -89,4 +89,4 @@ Homebrew will still install Python modules into Homebrew's `site-packages` and *
Virtualenv has a `--system-site-packages` switch to allow "global" (i.e. Homebrew's) `site-packages` to be accessible from within the virtualenv. Virtualenv has a `--system-site-packages` switch to allow "global" (i.e. Homebrew's) `site-packages` to be accessible from within the virtualenv.
## Why is Homebrew's Python being installed as a dependency? ## Why is Homebrew's Python being installed as a dependency?
Formulae that declare an unconditional dependency on the `"python"` or `"python3"` formulae are bottled against Homebrew's Python 2.7.x or 3.x and require it to be installed. Formulae that declare an unconditional dependency on the `"python"` or `"python@2"` formulae are bottled against Homebrew's Python 3.x or 2.7.x and require it to be installed.

View File

@ -96,7 +96,8 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note
By default, `deps` shows required and recommended dependencies for By default, `deps` shows required and recommended dependencies for
`formulae`. To include the `:build` type dependencies, pass `--include-build`. `formulae`. To include the `:build` type dependencies, pass `--include-build`.
Similarly, pass `--include-optional` to include `:optional` dependencies. Similarly, pass `--include-optional` to include `:optional` dependencies or
`--include-test` to include `:test` dependencies.
To skip `:recommended` type dependencies, pass `--skip-recommended`. To skip `:recommended` type dependencies, pass `--skip-recommended`.
To include requirements in addition to dependencies, pass `--include-requirements`. To include requirements in addition to dependencies, pass `--include-requirements`.
@ -109,8 +110,8 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note
If `--installed` is passed, output a tree for every installed formula. If `--installed` is passed, output a tree for every installed formula.
The `filters` placeholder is any combination of options `--include-build`, The `filters` placeholder is any combination of options `--include-build`,
`--include-optional`, `--skip-recommended`, and `--include-requirements` as `--include-optional`, `--include-test`, `--skip-recommended`, and
documented above. `--include-requirements` as documented above.
If `--annotate` is passed, the build, optional, and recommended dependencies If `--annotate` is passed, the build, optional, and recommended dependencies
are marked as such in the output. are marked as such in the output.
@ -121,7 +122,8 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note
dependencies of that formula. dependencies of that formula.
The `filters` placeholder is any combination of options `--include-build`, The `filters` placeholder is any combination of options `--include-build`,
`--include-optional`, and `--skip-recommended` as documented above. `--include-optional`, `--include-test`, and `--skip-recommended` as
documented above.
* `desc` `formula`: * `desc` `formula`:
Display `formula`'s name and one-line description. Display `formula`'s name and one-line description.
@ -559,8 +561,8 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note
repository's HEAD will be checked for updates when a new stable or devel repository's HEAD will be checked for updates when a new stable or devel
version has been released. version has been released.
If `formulae` are given, upgrade only the specified brews (but do so even If `formulae` are given, upgrade only the specified brews (unless they
if they are pinned; see `pin`, `unpin`). are pinned; see `pin`, `unpin`).
* `uses` [`--installed`] [`--recursive`] [`--include-build`] [`--include-optional`] [`--skip-recommended`] [`--devel`|`--HEAD`] `formulae`: * `uses` [`--installed`] [`--recursive`] [`--include-build`] [`--include-optional`] [`--skip-recommended`] [`--devel`|`--HEAD`] `formulae`:
Show the formulae that specify `formulae` as a dependency. When given Show the formulae that specify `formulae` as a dependency. When given

View File

@ -16,16 +16,16 @@ Applications should unconditionally bundle all of their Python-language dependen
### Python declarations ### Python declarations
Formulae for apps that require Python 3 **should** declare an unconditional dependency on `"python"`. These apps **must** work with the current Homebrew Python 3.x formula.
Applications that are compatible with Python 2 **should** use the Apple-provided system Python in `/usr/bin` on systems that provide Python 2.7. To do this, declare: Applications that are compatible with Python 2 **should** use the Apple-provided system Python in `/usr/bin` on systems that provide Python 2.7. To do this, declare:
```ruby ```ruby
depends_on "python" if MacOS.version <= :snow_leopard depends_on "python@2" if MacOS.version <= :snow_leopard
``` ```
No explicit Python dependency is needed on recent OS versions since `/usr/bin` is always in `PATH` for Homebrew formulae; on Leopard and older, the `python` in `PATH` is used if it's at least version 2.7, or else Homebrew's Python 2.7.x is installed. No explicit Python dependency is needed on recent OS versions since `/usr/bin` is always in `PATH` for Homebrew formulae; on Leopard and older, the `python` in `PATH` is used if it's at least version 2.7, or else Homebrew's Python 2.7.x is installed.
Formulae for apps that require Python 3 **should** declare an unconditional dependency on `"python3"`. These apps **must** work with the current Homebrew Python 3.x formula.
### Installing ### Installing
Applications should be installed into a Python [virtualenv](https://virtualenv.pypa.io/en/stable/) environment rooted in `libexec`. This prevents the app's Python modules from contaminating the system site-packages and vice versa. Applications should be installed into a Python [virtualenv](https://virtualenv.pypa.io/en/stable/) environment rooted in `libexec`. This prevents the app's Python modules from contaminating the system site-packages and vice versa.
@ -66,7 +66,7 @@ This is exactly the same as writing:
```ruby ```ruby
def install def install
# Create a virtualenv in `libexec`. If your app needs Python 3, make sure that # Create a virtualenv in `libexec`. If your app needs Python 3, make sure that
# `depends_on "python3"` is declared, and use `virtualenv_create(libexec, "python3")`. # `depends_on "python"` is declared, and use `virtualenv_create(libexec, "python")`.
venv = virtualenv_create(libexec) venv = virtualenv_create(libexec)
# Install all of the resources declared on the formula into the virtualenv. # Install all of the resources declared on the formula into the virtualenv.
venv.pip_install resources venv.pip_install resources
@ -121,9 +121,9 @@ in case you need to do different things for different resources.
## Bindings ## Bindings
Build bindings with the system Python by default (don't add an option) and they should be usable with any binary-compatible Python. If that isn't the case, it's an upstream bug; [here's some advice for resolving it](http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/). To add bindings for Python 3, please add `depends_on "python"`.
To add bindings for Python 3, please add `depends_on "python3" => :optional` and make the bindings conditional on `build.with?("python3")`. Build Python 2 bindings with the system Python by default (don't add an option) and they should be usable with any binary-compatible Python. If that isn't the case, it's an upstream bug; [here's some advice for resolving it](http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/).
### Dependencies ### Dependencies
@ -153,7 +153,9 @@ Sometimes we have to `inreplace` a `Makefile` to use our prefix for the Python b
### Python declarations ### Python declarations
Python 2 libraries do not need a `depends_on "python"` declaration; they will be built with the system Python, but should still be usable with any other Python 2.7. If this is not the case, it is an upstream bug; [here is some advice for resolving it](http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/). Libraries built for Python 3 should include `depends_on "python3"`, which will bottle against Homebrew's Python 3.x. If a library supports both Python 2.x and Python 3.x, the `"python3"` dependency should be `:optional`. Python 2.x libraries must function when they are installed against either the system Python or brewed Python. Libraries built for Python 3 should include `depends_on "python"`, which will bottle against Homebrew's Python 3.x. Python 2.x libraries must function when they are installed against either the system Python or brewed Python.
Python 2 libraries do not need a `depends_on "python@2"` declaration; they will be built with the system Python, but should still be usable with any other Python 2.7. If this is not the case, it is an upstream bug; [here is some advice for resolving it](http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/).
### Installing ### Installing

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BREW\-CASK" "1" "February 2018" "Homebrew" "brew-cask" .TH "BREW\-CASK" "1" "March 2018" "Homebrew" "brew-cask"
. .
.SH "NAME" .SH "NAME"
\fBbrew\-cask\fR \- a friendly binary installer for macOS \fBbrew\-cask\fR \- a friendly binary installer for macOS

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BREW" "1" "February 2018" "Homebrew" "brew" .TH "BREW" "1" "March 2018" "Homebrew" "brew"
. .
.SH "NAME" .SH "NAME"
\fBbrew\fR \- The missing package manager for macOS \fBbrew\fR \- The missing package manager for macOS
@ -107,7 +107,7 @@ If \fB\-\-full\-name\fR is passed, list dependencies by their full name\.
If \fB\-\-installed\fR is passed, only list those dependencies that are currently installed\. If \fB\-\-installed\fR is passed, only list those dependencies that are currently installed\.
. .
.IP .IP
By default, \fBdeps\fR shows required and recommended dependencies for \fIformulae\fR\. To include the \fB:build\fR type dependencies, pass \fB\-\-include\-build\fR\. Similarly, pass \fB\-\-include\-optional\fR to include \fB:optional\fR dependencies\. To skip \fB:recommended\fR type dependencies, pass \fB\-\-skip\-recommended\fR\. To include requirements in addition to dependencies, pass \fB\-\-include\-requirements\fR\. By default, \fBdeps\fR shows required and recommended dependencies for \fIformulae\fR\. To include the \fB:build\fR type dependencies, pass \fB\-\-include\-build\fR\. Similarly, pass \fB\-\-include\-optional\fR to include \fB:optional\fR dependencies or \fB\-\-include\-test\fR to include \fB:test\fR dependencies\. To skip \fB:recommended\fR type dependencies, pass \fB\-\-skip\-recommended\fR\. To include requirements in addition to dependencies, pass \fB\-\-include\-requirements\fR\.
. .
.TP .TP
\fBdeps\fR \fB\-\-tree\fR [\fB\-\-1\fR] [\fIfilters\fR] [\fB\-\-annotate\fR] (\fIformulae\fR|\fB\-\-installed\fR) \fBdeps\fR \fB\-\-tree\fR [\fB\-\-1\fR] [\fIfilters\fR] [\fB\-\-annotate\fR] (\fIformulae\fR|\fB\-\-installed\fR)
@ -120,7 +120,7 @@ If \fB\-\-1\fR is passed, only one level of children is displayed\.
If \fB\-\-installed\fR is passed, output a tree for every installed formula\. If \fB\-\-installed\fR is passed, output a tree for every installed formula\.
. .
.IP .IP
The \fIfilters\fR placeholder is any combination of options \fB\-\-include\-build\fR, \fB\-\-include\-optional\fR, \fB\-\-skip\-recommended\fR, and \fB\-\-include\-requirements\fR as documented above\. The \fIfilters\fR placeholder is any combination of options \fB\-\-include\-build\fR, \fB\-\-include\-optional\fR, \fB\-\-include\-test\fR, \fB\-\-skip\-recommended\fR, and \fB\-\-include\-requirements\fR as documented above\.
. .
.IP .IP
If \fB\-\-annotate\fR is passed, the build, optional, and recommended dependencies are marked as such in the output\. If \fB\-\-annotate\fR is passed, the build, optional, and recommended dependencies are marked as such in the output\.
@ -130,7 +130,7 @@ If \fB\-\-annotate\fR is passed, the build, optional, and recommended dependenci
Show dependencies for installed or all available formulae\. Every line of output starts with the formula name, followed by a colon and all direct dependencies of that formula\. Show dependencies for installed or all available formulae\. Every line of output starts with the formula name, followed by a colon and all direct dependencies of that formula\.
. .
.IP .IP
The \fIfilters\fR placeholder is any combination of options \fB\-\-include\-build\fR, \fB\-\-include\-optional\fR, and \fB\-\-skip\-recommended\fR as documented above\. The \fIfilters\fR placeholder is any combination of options \fB\-\-include\-build\fR, \fB\-\-include\-optional\fR, \fB\-\-include\-test\fR, and \fB\-\-skip\-recommended\fR as documented above\.
. .
.TP .TP
\fBdesc\fR \fIformula\fR \fBdesc\fR \fIformula\fR
@ -576,7 +576,7 @@ If \fB\-\-cleanup\fR is specified then remove previously installed \fIformula\fR
If \fB\-\-fetch\-HEAD\fR 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 \fB\-\-fetch\-HEAD\fR 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\.
. .
.IP .IP
If \fIformulae\fR are given, upgrade only the specified brews (but do so even if they are pinned; see \fBpin\fR, \fBunpin\fR)\. If \fIformulae\fR are given, upgrade only the specified brews (unless they are pinned; see \fBpin\fR, \fBunpin\fR)\.
. .
.TP .TP
\fBuses\fR [\fB\-\-installed\fR] [\fB\-\-recursive\fR] [\fB\-\-include\-build\fR] [\fB\-\-include\-optional\fR] [\fB\-\-skip\-recommended\fR] [\fB\-\-devel\fR|\fB\-\-HEAD\fR] \fIformulae\fR \fBuses\fR [\fB\-\-installed\fR] [\fB\-\-recursive\fR] [\fB\-\-include\-build\fR] [\fB\-\-include\-optional\fR] [\fB\-\-skip\-recommended\fR] [\fB\-\-devel\fR|\fB\-\-HEAD\fR] \fIformulae\fR