diff --git a/Library/Homebrew/.rubocop.yml b/Library/Homebrew/.rubocop.yml index 58b911ca9f..267641f022 100644 --- a/Library/Homebrew/.rubocop.yml +++ b/Library/Homebrew/.rubocop.yml @@ -88,3 +88,7 @@ Style/HashSyntax: # so many of these in formulae but none in here Style/TrailingBodyOnMethodDefinition: Enabled: true + +Rspec/ExpectActual: + Exclude: + - 'test/missing_formula_spec.rb' diff --git a/Library/Homebrew/PATH.rb b/Library/Homebrew/PATH.rb index de7167eb4b..263f26484e 100644 --- a/Library/Homebrew/PATH.rb +++ b/Library/Homebrew/PATH.rb @@ -32,7 +32,7 @@ class PATH end def to_ary - @paths + @paths.dup.to_ary end alias to_a to_ary diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index f31224ab25..d571f7e5c6 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -14,12 +14,13 @@ end require "pathname" HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent + require "English" unless $LOAD_PATH.include?(HOMEBREW_LIBRARY_PATH.to_s) $LOAD_PATH.unshift(HOMEBREW_LIBRARY_PATH.to_s) end + require "global" -require "tap" if ARGV == %w[--version] || ARGV == %w[-v] puts "Homebrew #{HOMEBREW_VERSION}" diff --git a/Library/Homebrew/build_environment.rb b/Library/Homebrew/build_environment.rb index 3c494428f0..da7d63cdf7 100644 --- a/Library/Homebrew/build_environment.rb +++ b/Library/Homebrew/build_environment.rb @@ -1,4 +1,3 @@ -require "set" class BuildEnvironment def initialize(*settings) diff --git a/Library/Homebrew/cask/lib/hbc.rb b/Library/Homebrew/cask/lib/hbc.rb index d865b31f2f..a013f4a323 100644 --- a/Library/Homebrew/cask/lib/hbc.rb +++ b/Library/Homebrew/cask/lib/hbc.rb @@ -1,5 +1,4 @@ require "hardware" -require "utils" require "hbc/artifact" require "hbc/audit" @@ -20,8 +19,6 @@ require "hbc/locations" require "hbc/config" require "hbc/macos" require "hbc/pkg" -require "hbc/qualified_token" -require "hbc/scopes" require "hbc/staged" require "hbc/system_command" require "hbc/topological_hash" @@ -32,7 +29,6 @@ require "hbc/version" module Hbc include Locations - include Scopes include Utils def self.init diff --git a/Library/Homebrew/cask/lib/hbc/artifact/abstract_uninstall.rb b/Library/Homebrew/cask/lib/hbc/artifact/abstract_uninstall.rb index d299733d89..9776a42ae7 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/abstract_uninstall.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/abstract_uninstall.rb @@ -1,4 +1,3 @@ -require "pathname" require "timeout" require "hbc/artifact/abstract_artifact" diff --git a/Library/Homebrew/cask/lib/hbc/cask.rb b/Library/Homebrew/cask/lib/hbc/cask.rb index 681130c1b1..410dcfe649 100644 --- a/Library/Homebrew/cask/lib/hbc/cask.rb +++ b/Library/Homebrew/cask/lib/hbc/cask.rb @@ -3,11 +3,20 @@ require "hbc/metadata" module Hbc class Cask + extend Enumerable extend Forwardable include Metadata attr_reader :token, :sourcefile_path, :config + def self.each + return to_enum unless block_given? + + Tap.flat_map(&:cask_files).each do |f| + yield CaskLoader::FromTapPathLoader.new(f).load + end + end + def tap return super if block_given? # Object#tap @tap @@ -43,11 +52,13 @@ module Hbc end def full_name - if @tap.nil? || @tap == Hbc.default_tap - token - else - "#{@tap}/#{token}" - end + return token if tap == Hbc.default_tap + qualified_token + end + + def qualified_token + return token if tap.nil? + "#{tap.name}/#{token}" end def installed? diff --git a/Library/Homebrew/cask/lib/hbc/caskroom.rb b/Library/Homebrew/cask/lib/hbc/caskroom.rb index b5c947f4b1..6c69e5fb8e 100644 --- a/Library/Homebrew/cask/lib/hbc/caskroom.rb +++ b/Library/Homebrew/cask/lib/hbc/caskroom.rb @@ -15,5 +15,17 @@ module Hbc SystemCommand.run("/usr/sbin/chown", args: [Utils.current_user, Hbc.caskroom], sudo: sudo) SystemCommand.run("/usr/bin/chgrp", args: ["admin", Hbc.caskroom], sudo: sudo) end + + def casks + Pathname.glob(Hbc.caskroom.join("*")).sort.select(&:directory?).map do |path| + token = path.basename.to_s + + if tap_path = CaskLoader.tap_paths(token).first + next CaskLoader::FromTapPathLoader.new(tap_path).load + end + + CaskLoader::FromPathLoader.new(Pathname.glob(path.join(".metadata/*/*/*/*.rb")).first).load + end + end end end diff --git a/Library/Homebrew/cask/lib/hbc/cli/audit.rb b/Library/Homebrew/cask/lib/hbc/cli/audit.rb index 35d82800c6..2b89a8d2c3 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/audit.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/audit.rb @@ -9,7 +9,7 @@ module Hbc end def run - failed_casks = casks(alternative: -> { Hbc.all }) + failed_casks = casks(alternative: -> { Cask.to_a }) .reject { |cask| audit(cask) } return if failed_casks.empty? diff --git a/Library/Homebrew/cask/lib/hbc/cli/info.rb b/Library/Homebrew/cask/lib/hbc/cli/info.rb index f12fe55648..991f0534ae 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/info.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/info.rb @@ -60,16 +60,12 @@ module Hbc end def self.repo_info(cask) - user, repo, token = QualifiedToken.parse(Hbc.all_tokens.detect { |t| t.split("/").last == cask.token }) + return if cask.tap.nil? - return if user.nil? || repo.nil? - - remote_tap = Tap.fetch(user, repo) - - url = if remote_tap.custom_remote? && !remote_tap.remote.nil? - remote_tap.remote + url = if cask.tap.custom_remote? && !cask.tap.remote.nil? + cask.tap.remote else - "#{remote_tap.default_remote}/blob/master/Casks/#{token}.rb" + "#{cask.tap.default_remote}/blob/master/Casks/#{cask.token}.rb" end puts "From: #{Formatter.url(url)}" diff --git a/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb b/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb index bdb1c0c30a..355f1a4d3f 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/internal_stanza.rb @@ -58,7 +58,7 @@ module Hbc @stanza = :artifacts end - casks(alternative: -> { Hbc.all }).each do |cask| + casks(alternative: -> { Cask.to_a }).each do |cask| print "#{cask}\t" if table? begin diff --git a/Library/Homebrew/cask/lib/hbc/cli/list.rb b/Library/Homebrew/cask/lib/hbc/cli/list.rb index 4a50ae74ad..788b0eede5 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/list.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/list.rb @@ -37,7 +37,7 @@ module Hbc end def list_installed - installed_casks = Hbc.installed + installed_casks = Caskroom.casks if one? puts installed_casks.map(&:to_s) diff --git a/Library/Homebrew/cask/lib/hbc/cli/outdated.rb b/Library/Homebrew/cask/lib/hbc/cli/outdated.rb index b0a84e8d26..593fea19da 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/outdated.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/outdated.rb @@ -10,7 +10,7 @@ module Hbc end def run - casks(alternative: -> { Hbc.installed }).each do |cask| + casks(alternative: -> { Caskroom.casks }).each do |cask| odebug "Checking update info of Cask #{cask}" self.class.list_if_outdated(cask, greedy?, verbose?) end diff --git a/Library/Homebrew/cask/lib/hbc/cli/search.rb b/Library/Homebrew/cask/lib/hbc/cli/search.rb index d56d0c81fe..480d7b5e54 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/search.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/search.rb @@ -3,7 +3,7 @@ module Hbc class Search < AbstractCommand def run if args.empty? - puts Formatter.columns(CLI.nice_listing(Hbc.all_tokens)) + puts Formatter.columns(CLI.nice_listing(Cask.map(&:qualified_token))) else results = self.class.search(*args) self.class.render_results(*results) @@ -30,6 +30,7 @@ module Hbc opoo "Error searching on GitHub: #{error}\n" [] end + matches.map do |match| tap = Tap.fetch(match["repository"]["full_name"]) next if tap.installed? @@ -42,7 +43,7 @@ module Hbc partial_matches = [] search_term = arguments.join(" ") search_regexp = extract_regexp arguments.first - all_tokens = CLI.nice_listing(Hbc.all_tokens) + all_tokens = CLI.nice_listing(Cask.map(&:qualified_token)) if search_regexp search_term = arguments.first partial_matches = all_tokens.grep(/#{search_regexp}/i) @@ -65,7 +66,7 @@ module Hbc return end - if !exact_match && partial_matches.empty? + if !exact_match && partial_matches.empty? && remote_matches.empty? puts "No Cask found for \"#{search_term}\"." return end diff --git a/Library/Homebrew/cask/lib/hbc/cli/style.rb b/Library/Homebrew/cask/lib/hbc/cli/style.rb index 261bed50b9..cb2e5e0537 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/style.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/style.rb @@ -27,7 +27,7 @@ module Hbc def cask_paths @cask_paths ||= if args.empty? - Hbc.all_tapped_cask_dirs + Tap.map(&:cask_dir).select(&:directory?) elsif args.any? { |file| File.exist?(file) } args else diff --git a/Library/Homebrew/cask/lib/hbc/cli/upgrade.rb b/Library/Homebrew/cask/lib/hbc/cli/upgrade.rb index 808b64c4b7..276b180aa1 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/upgrade.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/upgrade.rb @@ -13,7 +13,7 @@ module Hbc def run outdated_casks = casks(alternative: lambda { - Hbc.installed.select do |cask| + Caskroom.casks.select do |cask| cask.outdated?(greedy?) end }).select { |cask| cask.outdated?(true) } diff --git a/Library/Homebrew/cask/lib/hbc/container/bzip2.rb b/Library/Homebrew/cask/lib/hbc/container/bzip2.rb index 9f2a59bb8a..efa95376a2 100644 --- a/Library/Homebrew/cask/lib/hbc/container/bzip2.rb +++ b/Library/Homebrew/cask/lib/hbc/container/bzip2.rb @@ -1,5 +1,3 @@ -require "tmpdir" - require "hbc/container/base" module Hbc diff --git a/Library/Homebrew/cask/lib/hbc/container/cab.rb b/Library/Homebrew/cask/lib/hbc/container/cab.rb index 327aece6ea..403abcc0fd 100644 --- a/Library/Homebrew/cask/lib/hbc/container/cab.rb +++ b/Library/Homebrew/cask/lib/hbc/container/cab.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/dmg.rb b/Library/Homebrew/cask/lib/hbc/container/dmg.rb index c0e43f68a0..fcb9b5739d 100644 --- a/Library/Homebrew/cask/lib/hbc/container/dmg.rb +++ b/Library/Homebrew/cask/lib/hbc/container/dmg.rb @@ -1,4 +1,3 @@ -require "set" require "tempfile" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/generic_unar.rb b/Library/Homebrew/cask/lib/hbc/container/generic_unar.rb index 63ab917ea2..6a05edb8d0 100644 --- a/Library/Homebrew/cask/lib/hbc/container/generic_unar.rb +++ b/Library/Homebrew/cask/lib/hbc/container/generic_unar.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/gpg.rb b/Library/Homebrew/cask/lib/hbc/container/gpg.rb index 09c75468ac..ae162565e8 100644 --- a/Library/Homebrew/cask/lib/hbc/container/gpg.rb +++ b/Library/Homebrew/cask/lib/hbc/container/gpg.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/gzip.rb b/Library/Homebrew/cask/lib/hbc/container/gzip.rb index d3dd7b8fd0..4f91c3879c 100644 --- a/Library/Homebrew/cask/lib/hbc/container/gzip.rb +++ b/Library/Homebrew/cask/lib/hbc/container/gzip.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/lzma.rb b/Library/Homebrew/cask/lib/hbc/container/lzma.rb index 1e165ba2a7..7d50199bc8 100644 --- a/Library/Homebrew/cask/lib/hbc/container/lzma.rb +++ b/Library/Homebrew/cask/lib/hbc/container/lzma.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/tar.rb b/Library/Homebrew/cask/lib/hbc/container/tar.rb index eb646c816f..f5340174e4 100644 --- a/Library/Homebrew/cask/lib/hbc/container/tar.rb +++ b/Library/Homebrew/cask/lib/hbc/container/tar.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/xar.rb b/Library/Homebrew/cask/lib/hbc/container/xar.rb index a0165ca57e..9121e726d8 100644 --- a/Library/Homebrew/cask/lib/hbc/container/xar.rb +++ b/Library/Homebrew/cask/lib/hbc/container/xar.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/container/xz.rb b/Library/Homebrew/cask/lib/hbc/container/xz.rb index 4086ae1886..408e0917a5 100644 --- a/Library/Homebrew/cask/lib/hbc/container/xz.rb +++ b/Library/Homebrew/cask/lib/hbc/container/xz.rb @@ -1,4 +1,3 @@ -require "tmpdir" require "hbc/container/base" diff --git a/Library/Homebrew/cask/lib/hbc/dsl.rb b/Library/Homebrew/cask/lib/hbc/dsl.rb index 9a88f1b624..9d229e2880 100644 --- a/Library/Homebrew/cask/lib/hbc/dsl.rb +++ b/Library/Homebrew/cask/lib/hbc/dsl.rb @@ -1,4 +1,3 @@ -require "set" require "locale" require "hbc/artifact" diff --git a/Library/Homebrew/cask/lib/hbc/locations.rb b/Library/Homebrew/cask/lib/hbc/locations.rb index 40ba2989f0..fea696e5b0 100644 --- a/Library/Homebrew/cask/lib/hbc/locations.rb +++ b/Library/Homebrew/cask/lib/hbc/locations.rb @@ -1,4 +1,3 @@ -require "tap" module Hbc module Locations diff --git a/Library/Homebrew/cask/lib/hbc/macos.rb b/Library/Homebrew/cask/lib/hbc/macos.rb index d47e04fb24..c983c1e24e 100644 --- a/Library/Homebrew/cask/lib/hbc/macos.rb +++ b/Library/Homebrew/cask/lib/hbc/macos.rb @@ -1,4 +1,3 @@ -require "set" require "os/mac/version" @@ -239,26 +238,35 @@ module OS # TODO: There should be a way to specify a containing # directory under which nothing can be deleted. - UNDELETABLE_DIRS = [ + UNDELETABLE_PATHS = [ "~/", "~/Applications", + "~/Applications/.localized", "~/Desktop", + "~/Desktop/.localized", "~/Documents", + "~/Documents/.localized", "~/Downloads", + "~/Downloads/.localized", "~/Mail", "~/Movies", + "~/Movies/.localized", "~/Music", + "~/Music/.localized", "~/Music/iTunes", "~/Music/iTunes/iTunes Music", "~/Music/iTunes/Album Artwork", "~/News", "~/Pictures", + "~/Pictures/.localized", "~/Pictures/Desktops", "~/Pictures/Photo Booth", "~/Pictures/iChat Icons", "~/Pictures/iPhoto Library", "~/Public", + "~/Public/.localized", "~/Sites", + "~/Sites/.localized", "~/Library", "~/Library/.localized", "~/Library/Accessibility", @@ -365,17 +373,17 @@ module OS "~/Library/Widgets", "~/Library/Workflows", ] - .map { |x| Pathname(x.sub(%r{^~(?=(/|$))}, Dir.home)).expand_path } - .to_set - .union(SYSTEM_DIRS) - .freeze + .map { |path| Pathname(path.sub(%r{^~(?=(/|$))}, Dir.home)).expand_path } + .to_set + .union(SYSTEM_DIRS) + .freeze def system_dir?(dir) SYSTEM_DIRS.include?(Pathname.new(dir).expand_path) end - def undeletable?(dir) - UNDELETABLE_DIRS.include?(Pathname.new(dir).expand_path) + def undeletable?(path) + UNDELETABLE_PATHS.include?(Pathname.new(path).expand_path) end end end diff --git a/Library/Homebrew/cask/lib/hbc/metadata.rb b/Library/Homebrew/cask/lib/hbc/metadata.rb index 344c38ceea..030b18dd9f 100644 --- a/Library/Homebrew/cask/lib/hbc/metadata.rb +++ b/Library/Homebrew/cask/lib/hbc/metadata.rb @@ -22,7 +22,7 @@ module Hbc end path = if timestamp == :latest - Pathname.glob(metadata_versioned_path(version: version).join("*")).sort.last + Pathname.glob(metadata_versioned_path(version: version).join("*")).max else timestamp = new_timestamp if timestamp == :now metadata_versioned_path(version: version).join(timestamp) diff --git a/Library/Homebrew/cask/lib/hbc/qualified_token.rb b/Library/Homebrew/cask/lib/hbc/qualified_token.rb deleted file mode 100644 index 09eedef1b3..0000000000 --- a/Library/Homebrew/cask/lib/hbc/qualified_token.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Hbc - module QualifiedToken - def self.parse(arg) - return nil unless arg.is_a?(String) - return nil unless match = arg.downcase.match(HOMEBREW_TAP_CASK_REGEX) - user, repo, token = match.captures - odebug "[user, repo, token] might be [#{user}, #{repo}, #{token}]" - [user, repo, token] - end - end -end diff --git a/Library/Homebrew/cask/lib/hbc/scopes.rb b/Library/Homebrew/cask/lib/hbc/scopes.rb deleted file mode 100644 index a469ae0fa6..0000000000 --- a/Library/Homebrew/cask/lib/hbc/scopes.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Hbc - module Scopes - def self.included(base) - base.extend(ClassMethods) - end - - module ClassMethods - def all - all_tokens.map(&CaskLoader.public_method(:load)) - end - - def all_tapped_cask_dirs - Tap.map(&:cask_dir).select(&:directory?) - end - - def all_tokens - Tap.flat_map do |t| - t.cask_files.map do |p| - "#{t.name}/#{File.basename(p, ".rb")}" - end - end - end - - def installed - # CaskLoader.load has some DWIM which is slow. Optimize here - # by spoon-feeding CaskLoader.load fully-qualified paths. - # TODO: speed up Hbc::Source::Tapped (main perf drag is calling Hbc.all_tokens repeatedly) - # TODO: ability to specify expected source when calling CaskLoader.load (minor perf benefit) - Pathname.glob(caskroom.join("*")) - .sort - .map do |caskroom_path| - token = caskroom_path.basename.to_s - - path_to_cask = all_tapped_cask_dirs.find do |tap_dir| - tap_dir.join("#{token}.rb").exist? - end - - if path_to_cask - CaskLoader.load(path_to_cask.join("#{token}.rb")) - else - CaskLoader.load(token) - end - end - end - end - end -end diff --git a/Library/Homebrew/cask/lib/hbc/staged.rb b/Library/Homebrew/cask/lib/hbc/staged.rb index da097e0cf9..fa2439a2e5 100644 --- a/Library/Homebrew/cask/lib/hbc/staged.rb +++ b/Library/Homebrew/cask/lib/hbc/staged.rb @@ -33,6 +33,7 @@ module Hbc def set_ownership(paths, user: current_user, group: "staff") full_paths = remove_nonexistent(paths) return if full_paths.empty? + ohai "Changing ownership of paths required by #{@cask}; your password may be necessary" @command.run!("/usr/sbin/chown", args: ["-R", "--", "#{user}:#{group}"] + full_paths, sudo: true) end diff --git a/Library/Homebrew/cask/lib/hbc/utils.rb b/Library/Homebrew/cask/lib/hbc/utils.rb index 0f44c0157f..01ab4dad7f 100644 --- a/Library/Homebrew/cask/lib/hbc/utils.rb +++ b/Library/Homebrew/cask/lib/hbc/utils.rb @@ -4,17 +4,6 @@ require "stringio" BUG_REPORTS_URL = "https://github.com/caskroom/homebrew-cask#reporting-bugs".freeze -class Buffer < StringIO - extend Predicable - - attr_predicate :tty? - - def initialize(tty = false) - super() - @tty = tty - end -end - # global methods def odebug(title, *sput) diff --git a/Library/Homebrew/caveats.rb b/Library/Homebrew/caveats.rb index a289a12202..9fb788a46f 100644 --- a/Library/Homebrew/caveats.rb +++ b/Library/Homebrew/caveats.rb @@ -1,4 +1,3 @@ -require "forwardable" require "language/python" class Caveats diff --git a/Library/Homebrew/cli_parser.rb b/Library/Homebrew/cli_parser.rb index 8a6e15abb7..dd467f3fc6 100644 --- a/Library/Homebrew/cli_parser.rb +++ b/Library/Homebrew/cli_parser.rb @@ -11,16 +11,20 @@ module Homebrew def initialize(&block) @parser = OptionParser.new @parsed_args = OpenStruct.new + # undefine tap to allow --tap argument + @parsed_args.instance_eval { undef tap } 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) + global_switch = names.first.is_a?(Symbol) + names, env = common_switch(*names) if global_switch @parser.on(*names, description) do - enable_switch(*names) + enable_switch(*names, global_switch) end - enable_switch(*names) if !env.nil? && !ENV["HOMEBREW_#{env.to_s.upcase}"].nil? + enable_switch(*names, global_switch) if !env.nil? && + !ENV["HOMEBREW_#{env.to_s.upcase}"].nil? end def comma_array(name, description: nil) @@ -30,14 +34,15 @@ module Homebrew end end - def flag(name, description: nil, required: false) - if required - option_required = OptionParser::REQUIRED_ARGUMENT + def flag(name, description: nil) + if name.end_with? "=" + required = OptionParser::REQUIRED_ARGUMENT + name.chomp! "=" else - option_required = OptionParser::OPTIONAL_ARGUMENT + required = OptionParser::OPTIONAL_ARGUMENT end description = option_to_description(name) if description.nil? - @parser.on(name, description, option_required) do |option_value| + @parser.on(name, description, required) do |option_value| @parsed_args[option_to_name(name)] = option_value end end @@ -47,27 +52,33 @@ module Homebrew end def option_to_description(*names) - names.map { |name| name.to_s.sub(/\A--?/, "").tr("-", " ") }.sort.last + names.map { |name| name.to_s.sub(/\A--?/, "").tr("-", " ") }.max end def parse(cmdline_args = ARGV) - @parser.parse!(cmdline_args) + @parser.parse(cmdline_args) @parsed_args end private - def enable_switch(*names) + def enable_switch(*names, global_switch) names.each do |name| + if global_switch + Homebrew.args["#{option_to_name(name)}?"] = true + next + end @parsed_args["#{option_to_name(name)}?"] = true end end + # These are common/global switches accessible throughout Homebrew def common_switch(name) case name when :quiet then [["-q", "--quiet"], :quiet] when :verbose then [["-v", "--verbose"], :verbose] when :debug then [["-d", "--debug"], :debug] + when :force then [["-f", "--force"], :force] else name end end diff --git a/Library/Homebrew/cmd/--repository.rb b/Library/Homebrew/cmd/--repository.rb index 006d4cd5d3..6f6f8d31ec 100644 --- a/Library/Homebrew/cmd/--repository.rb +++ b/Library/Homebrew/cmd/--repository.rb @@ -4,8 +4,6 @@ #: * `--repository` `/`: #: Display where tap `/`'s directory is located. -require "tap" - module Homebrew module_function diff --git a/Library/Homebrew/cmd/cleanup.rb b/Library/Homebrew/cmd/cleanup.rb index 290b748de2..2fba06e20f 100644 --- a/Library/Homebrew/cmd/cleanup.rb +++ b/Library/Homebrew/cmd/cleanup.rb @@ -12,7 +12,6 @@ #: deleted. If you want to delete those too: `rm -rf $(brew --cache)` require "cleanup" -require "utils" module Homebrew module_function diff --git a/Library/Homebrew/cmd/doctor.rb b/Library/Homebrew/cmd/doctor.rb index 4e439fa0a3..216987077c 100644 --- a/Library/Homebrew/cmd/doctor.rb +++ b/Library/Homebrew/cmd/doctor.rb @@ -28,7 +28,6 @@ module Homebrew slow_checks = %w[ check_for_broken_symlinks check_missing_deps - check_for_linked_keg_only_brews ] methods = (checks.all.sort - slow_checks) + slow_checks else diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb index c30ee85cd9..df87b327c8 100644 --- a/Library/Homebrew/cmd/gist-logs.rb +++ b/Library/Homebrew/cmd/gist-logs.rb @@ -119,7 +119,7 @@ module Homebrew def create_issue(repo, title, body) url = "https://api.github.com/repos/#{repo}/issues" data = { "title" => title, "body" => body } - scopes = GitHub::CREATE_ISSUE_SCOPES + scopes = GitHub::CREATE_ISSUE_FORK_OR_PR_SCOPES GitHub.open_api(url, data: data, scopes: scopes)["html_url"] end diff --git a/Library/Homebrew/cmd/help.rb b/Library/Homebrew/cmd/help.rb index 2b1e7c5049..fa5727816e 100644 --- a/Library/Homebrew/cmd/help.rb +++ b/Library/Homebrew/cmd/help.rb @@ -1,7 +1,7 @@ HOMEBREW_HELP = <<~EOS.freeze Example usage: brew search [TEXT|/REGEX/] - brew (info|home|options) [FORMULA...] + brew info [FORMULA...] brew install FORMULA... brew update brew upgrade [FORMULA...] @@ -11,17 +11,17 @@ HOMEBREW_HELP = <<~EOS.freeze Troubleshooting: brew config brew doctor - brew install -vd FORMULA + brew install --verbose --debug FORMULA - Developers: + Contributing: brew create [URL [--no-fetch]] brew edit [FORMULA...] - https://docs.brew.sh/Formula-Cookbook Further help: - man brew + brew commands brew help [COMMAND] - brew home + man brew + https://docs.brew.sh EOS # NOTE Keep the lenth of vanilla --help less than 25 lines! diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index a0e1cd4756..cfe8b13d87 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -60,7 +60,7 @@ module Homebrew rescue FormulaUnavailableError => e ofail e.message # No formula with this name, try a missing formula lookup - if (reason = Homebrew::MissingFormula.reason(f)) + if (reason = MissingFormula.reason(f)) $stderr.puts reason end end diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index e26499a21f..21ea88193a 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -71,7 +71,6 @@ require "missing_formula" require "diagnostic" require "cmd/search" require "formula_installer" -require "tap" require "hardware" require "development_tools" @@ -166,7 +165,8 @@ module Homebrew formulae << f else opoo <<~EOS - #{f.full_name} #{f.pkg_version} is already installed + #{f.full_name} #{f.pkg_version} is already installed and up-to-date + To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}` EOS end elsif (ARGV.build_head? && new_head_installed) || prefix_installed @@ -190,12 +190,17 @@ module Homebrew EOS elsif !f.linked? || f.keg_only? msg = <<~EOS - #{msg}, it's just not linked. + #{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 + else + msg = <<~EOS + #{msg} and up-to-date + To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}` + EOS end opoo msg if msg elsif !f.any_version_installed? && old_formula = f.old_installed_formulae.first @@ -252,7 +257,7 @@ module Homebrew end ofail e.message - if (reason = Homebrew::MissingFormula.reason(e.name)) + if (reason = MissingFormula.reason(e.name)) $stderr.puts reason return end diff --git a/Library/Homebrew/cmd/leaves.rb b/Library/Homebrew/cmd/leaves.rb index 42fa18a28a..ec5238c2a1 100644 --- a/Library/Homebrew/cmd/leaves.rb +++ b/Library/Homebrew/cmd/leaves.rb @@ -3,7 +3,6 @@ require "formula" require "tab" -require "set" module Homebrew module_function diff --git a/Library/Homebrew/cmd/linkapps.rb b/Library/Homebrew/cmd/linkapps.rb deleted file mode 100644 index 1bec67a047..0000000000 --- a/Library/Homebrew/cmd/linkapps.rb +++ /dev/null @@ -1,67 +0,0 @@ -#: @hide_from_man_page -#: * `linkapps` [`--local`] []: -#: Find installed formulae that provide `.app`-style macOS apps and symlink them -#: into `/Applications`, allowing for easier access (deprecated). -#: -#: Unfortunately `brew linkapps` cannot behave nicely with e.g. Spotlight using -#: either aliases or symlinks and Homebrew formulae do not build "proper" `.app` -#: bundles that can be relocated. Instead, please consider using `brew cask` and -#: migrate formulae using `.app`s to casks. - -require "keg" -require "formula" - -module Homebrew - module_function - - def linkapps - odeprecated "'brew linkapps'" - - target_dir = linkapps_target(local: ARGV.include?("--local")) - - unless target_dir.directory? - opoo "#{target_dir} does not exist, stopping." - puts "Run `mkdir #{target_dir}` first." - exit 1 - end - - if ARGV.named.empty? - kegs = Formula.racks.map do |rack| - keg = rack.subdirs.map { |d| Keg.new(d) } - next if keg.empty? - keg.detect(&:linked?) || keg.max_by(&:version) - end - else - kegs = ARGV.kegs - end - - link_count = 0 - kegs.each do |keg| - keg.apps.each do |app| - puts "Linking: #{app}" - target_app = target_dir/app.basename - - if target_app.exist? && !target_app.symlink? - onoe "#{target_app} already exists, skipping." - next - end - - # We prefer system `ln` over `FileUtils.ln_sf` because the latter seems - # to have weird failure conditions (that were observed in the past). - system "ln", "-sf", app, target_dir - link_count += 1 - end - end - - if link_count.zero? - puts "No apps linked to #{target_dir}" if ARGV.verbose? - else - puts "Linked #{Formatter.pluralize(link_count, "app")} to #{target_dir}" - end - end - - def linkapps_target(opts = {}) - local = opts.fetch(:local, false) - Pathname.new(local ? "~/Applications" : "/Applications").expand_path - end -end diff --git a/Library/Homebrew/cmd/missing.rb b/Library/Homebrew/cmd/missing.rb index 707ad68345..a12fd5460e 100644 --- a/Library/Homebrew/cmd/missing.rb +++ b/Library/Homebrew/cmd/missing.rb @@ -4,6 +4,8 @@ #: #: If `--hide=` is passed, act as if none of are installed. #: should be a comma-separated list of formulae. +#: +#: `missing` exits with a non-zero status if any formulae are missing dependencies. require "formula" require "tab" @@ -25,6 +27,7 @@ module Homebrew missing = f.missing_dependencies(hide: ARGV.values("hide")) next if missing.empty? + Homebrew.failed = true print "#{f}: " if ff.size > 1 puts missing.join(" ") end diff --git a/Library/Homebrew/cmd/prune.rb b/Library/Homebrew/cmd/prune.rb index 7ec2838bae..3270066131 100644 --- a/Library/Homebrew/cmd/prune.rb +++ b/Library/Homebrew/cmd/prune.rb @@ -1,15 +1,12 @@ #: * `prune` [`--dry-run`]: #: Remove dead symlinks from the Homebrew prefix. This is generally not -#: needed, but can be useful when doing DIY installations. Also remove broken -#: app symlinks from `/Applications` and `~/Applications` that were previously -#: created by `brew linkapps`. +#: needed, but can be useful when doing DIY installations. #: #: If `--dry-run` or `-n` is passed, show what would be removed, but do not #: actually remove anything. require "keg" require "cmd/tap" -require "cmd/unlinkapps" module Homebrew module_function @@ -49,17 +46,15 @@ module Homebrew end end - unless ARGV.dry_run? - if ObserverPathnameExtension.total.zero? - puts "Nothing pruned" if ARGV.verbose? - else - n, d = ObserverPathnameExtension.counts - print "Pruned #{n} symbolic links " - print "and #{d} directories " if d.positive? - puts "from #{HOMEBREW_PREFIX}" - end - end + return if ARGV.dry_run? - unlinkapps_prune(dry_run: ARGV.dry_run?, quiet: true) + if ObserverPathnameExtension.total.zero? + puts "Nothing pruned" if ARGV.verbose? + else + n, d = ObserverPathnameExtension.counts + print "Pruned #{n} symbolic links " + print "and #{d} directories " if d.positive? + puts "from #{HOMEBREW_PREFIX}" + end end end diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index 4ba5247f12..0f01afa46f 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -15,8 +15,6 @@ require "formula" require "missing_formula" -require "utils" -require "official_taps" require "descriptions" module Homebrew @@ -66,7 +64,7 @@ module Homebrew count = local_results.length + tap_results.length ohai "Searching blacklisted, migrated and deleted formulae..." - if reason = Homebrew::MissingFormula.reason(query, silent: true) + if reason = MissingFormula.reason(query, silent: true) if count.positive? puts puts "If you meant #{query.inspect} specifically:" @@ -110,15 +108,22 @@ module Homebrew $stderr.puts Formatter.headline("Searching taps on GitHub...", color: :blue) end - valid_dirnames = ["Formula", "HomebrewFormula", "Casks", "."].freeze - matches = GitHub.search_code(user: ["Homebrew", "caskroom"], filename: query, extension: "rb") - + matches = begin + GitHub.search_code( + user: ["Homebrew", "caskroom"], + path: ["Formula", "HomebrewFormula", "Casks", "."], + filename: query, + extension: "rb", + ) + rescue GitHub::Error => error + opoo "Error searching on GitHub: #{error}\n" + [] + end matches.map do |match| - dirname, filename = File.split(match["path"]) - next unless valid_dirnames.include?(dirname) + filename = File.basename(match["path"], ".rb") tap = Tap.fetch(match["repository"]["full_name"]) next if tap.installed? && match["repository"]["owner"]["login"] != "caskroom" - "#{tap.name}/#{File.basename(filename, ".rb")}" + "#{tap.name}/#{filename}" end.compact end diff --git a/Library/Homebrew/cmd/style.rb b/Library/Homebrew/cmd/style.rb index 76d961a7fe..e41f10f97a 100644 --- a/Library/Homebrew/cmd/style.rb +++ b/Library/Homebrew/cmd/style.rb @@ -19,7 +19,6 @@ #: #: Exits with a non-zero status if any style violations are found. -require "utils" require "json" require "open3" diff --git a/Library/Homebrew/cmd/switch.rb b/Library/Homebrew/cmd/switch.rb index 8a378aed79..b0ac32626e 100644 --- a/Library/Homebrew/cmd/switch.rb +++ b/Library/Homebrew/cmd/switch.rb @@ -1,5 +1,5 @@ -#: * `switch` : -#: Symlink all of the specific of 's install to Homebrew prefix. +#: * `switch` : +#: Symlink all of the specific of 's install to Homebrew prefix. require "formula" require "keg" @@ -9,14 +9,15 @@ module Homebrew module_function def switch - if ARGV.named.length != 2 - onoe "Usage: brew switch " + name = ARGV.first + + usage = "Usage: brew switch " + + unless name + onoe usage exit 1 end - name = ARGV.shift - version = ARGV.shift - rack = Formulary.to_rack(name) unless rack.directory? @@ -24,13 +25,21 @@ module Homebrew exit 2 end - # Does the target version exist? + versions = rack.subdirs + .map { |d| Keg.new(d).version } + .sort + .join(", ") + version = ARGV[1] + + if !version || ARGV.named.length > 2 + onoe usage + puts "#{name} installed versions: #{versions}" + exit 1 + end + unless (rack/version).directory? onoe "#{name} does not have a version \"#{version}\" in the Cellar." - - versions = rack.subdirs.map { |d| Keg.new(d).version }.sort - puts "Versions available: #{versions.join(", ")}" - + puts "#{name} installed versions: #{versions}" exit 3 end diff --git a/Library/Homebrew/cmd/tap-info.rb b/Library/Homebrew/cmd/tap-info.rb index 26daa1a8ae..b2d9ee5088 100644 --- a/Library/Homebrew/cmd/tap-info.rb +++ b/Library/Homebrew/cmd/tap-info.rb @@ -15,8 +15,6 @@ #: See the docs for examples of using the JSON output: #: -require "tap" - module Homebrew module_function diff --git a/Library/Homebrew/cmd/tap-pin.rb b/Library/Homebrew/cmd/tap-pin.rb index 41957f2652..505720f30d 100644 --- a/Library/Homebrew/cmd/tap-pin.rb +++ b/Library/Homebrew/cmd/tap-pin.rb @@ -2,8 +2,6 @@ #: Pin , prioritizing its formulae over core when formula names are supplied #: by the user. See also `tap-unpin`. -require "tap" - module Homebrew module_function diff --git a/Library/Homebrew/cmd/tap-unpin.rb b/Library/Homebrew/cmd/tap-unpin.rb index 05bfc7c8b9..0c7c9ee020 100644 --- a/Library/Homebrew/cmd/tap-unpin.rb +++ b/Library/Homebrew/cmd/tap-unpin.rb @@ -1,8 +1,6 @@ #: * `tap-unpin` : #: Unpin so its formulae are no longer prioritized. See also `tap-pin`. -require "tap" - module Homebrew module_function diff --git a/Library/Homebrew/cmd/tap.rb b/Library/Homebrew/cmd/tap.rb index fa520e2c56..94362f7fe4 100644 --- a/Library/Homebrew/cmd/tap.rb +++ b/Library/Homebrew/cmd/tap.rb @@ -1,7 +1,7 @@ #: * `tap`: #: List all installed taps. #: -#: * `tap` [`--full`] `/` []: +#: * `tap` [`--full`] [`--force-auto-update`] `/` []: #: Tap a formula repository. #: #: With unspecified, taps a formula repository from GitHub using HTTPS. @@ -18,6 +18,10 @@ #: if `--full` is passed, a full clone will be used. To convert a shallow copy #: to a full copy, you can retap passing `--full` without first untapping. #: +#: By default, only taps hosted on GitHub are auto-updated (for performance +#: reasons). If `--force-auto-update` is passed, this tap will be auto-updated +#: even if it is not hosted on GitHub. +#: #: `tap` is re-runnable and exits successfully if there's nothing to do. #: However, retapping with a different will cause an exception, so first #: `untap` if you need to modify the . @@ -25,14 +29,9 @@ #: * `tap` `--repair`: #: Migrate tapped formulae from symlink-based to directory-based structure. #: -#: * `tap` `--list-official`: -#: List all official taps. -#: #: * `tap` `--list-pinned`: #: List all pinned taps. -require "tap" - module Homebrew module_function @@ -40,8 +39,7 @@ module Homebrew if ARGV.include? "--repair" Tap.each(&:link_completions_and_manpages) elsif ARGV.include? "--list-official" - require "official_taps" - puts OFFICIAL_TAPS.map { |t| "homebrew/#{t}" } + odeprecated("brew tap --list-official") elsif ARGV.include? "--list-pinned" puts Tap.select(&:pinned?).map(&:name) elsif ARGV.named.empty? @@ -50,6 +48,7 @@ module Homebrew tap = Tap.fetch(ARGV.named[0]) begin tap.install clone_target: ARGV.named[1], + force_auto_update: force_auto_update?, full_clone: full_clone?, quiet: ARGV.quieter? rescue TapRemoteMismatchError => e @@ -62,4 +61,9 @@ module Homebrew def full_clone? ARGV.include?("--full") || ARGV.homebrew_developer? end + + def force_auto_update? + # if no relevant flag is present, return nil, meaning "no change" + true if ARGV.include?("--force-auto-update") + end end diff --git a/Library/Homebrew/cmd/unlinkapps.rb b/Library/Homebrew/cmd/unlinkapps.rb deleted file mode 100644 index 721e4d6390..0000000000 --- a/Library/Homebrew/cmd/unlinkapps.rb +++ /dev/null @@ -1,79 +0,0 @@ -#: @hide_from_man_page -#: * `unlinkapps` [`--local`] [`--dry-run`] []: -#: Remove symlinks created by `brew linkapps` from `/Applications` (deprecated). -#: -#: Unfortunately `brew linkapps` cannot behave nicely with e.g. Spotlight using -#: either aliases or symlinks and Homebrew formulae do not build "proper" `.app` -#: bundles that can be relocated. Instead, please consider using `brew cask` and -#: migrate formulae using `.app`s to casks. - -require "cmd/linkapps" - -module Homebrew - module_function - - def unlinkapps - odeprecated "'brew unlinkapps'" - - target_dir = linkapps_target(local: ARGV.include?("--local")) - - unlinkapps_from_dir(target_dir, dry_run: ARGV.dry_run?) - end - - def unlinkapps_prune(opts = {}) - opts = opts.merge(prune: true) - unlinkapps_from_dir(linkapps_target(local: false), opts) - unlinkapps_from_dir(linkapps_target(local: true), opts) - end - - def unlinkapps_from_dir(target_dir, opts = {}) - return unless target_dir.directory? - dry_run = opts.fetch(:dry_run, false) - quiet = opts.fetch(:quiet, false) - - apps = Pathname.glob("#{target_dir}/*.app").select do |app| - unlinkapps_unlink?(app, opts) - end - - ObserverPathnameExtension.reset_counts! - - app_kind = opts.fetch(:prune, false) ? " (broken link)" : "" - apps.each do |app| - app.extend(ObserverPathnameExtension) - if dry_run - puts "Would unlink#{app_kind}: #{app}" - else - puts "Unlinking#{app_kind}: #{app}" unless quiet - app.unlink - end - end - - return if dry_run - - if ObserverPathnameExtension.total.zero? - puts "No apps unlinked from #{target_dir}" if ARGV.verbose? - else - n = ObserverPathnameExtension.total - puts "Unlinked #{Formatter.pluralize(n, "app")} from #{target_dir}" - end - end - - UNLINKAPPS_PREFIXES = %W[ - #{HOMEBREW_CELLAR}/ - #{HOMEBREW_PREFIX}/opt/ - ].freeze - - def unlinkapps_unlink?(target_app, opts = {}) - # Skip non-symlinks and symlinks that don't point into the Homebrew prefix. - app = target_app.readlink.to_s if target_app.symlink? - return false unless app&.start_with?(*UNLINKAPPS_PREFIXES) - - if opts.fetch(:prune, false) - !File.exist?(app) # Remove only broken symlinks in prune mode. - elsif ARGV.named.empty? - true - else - ARGV.kegs.any? { |keg| app.start_with?("#{keg}/", "#{keg.opt_record}/") } - end - end -end diff --git a/Library/Homebrew/cmd/untap.rb b/Library/Homebrew/cmd/untap.rb index 0d363b7b58..1b4bf109dd 100644 --- a/Library/Homebrew/cmd/untap.rb +++ b/Library/Homebrew/cmd/untap.rb @@ -1,8 +1,6 @@ #: * `untap` : #: Remove a tapped repository. -require "tap" - module Homebrew module_function diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index d241d17b06..b2d5dfdbed 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -7,7 +7,6 @@ require "migrator" require "formulary" require "descriptions" require "cleanup" -require "utils" module Homebrew module_function diff --git a/Library/Homebrew/cmd/update.sh b/Library/Homebrew/cmd/update.sh index f0fbdffafa..d3dae2be31 100644 --- a/Library/Homebrew/cmd/update.sh +++ b/Library/Homebrew/cmd/update.sh @@ -493,8 +493,12 @@ EOS [[ -z "$HOMEBREW_UPDATE_FORCE" ]] && [[ "$UPSTREAM_SHA_HTTP_CODE" = "304" ]] && exit elif [[ -n "$HOMEBREW_UPDATE_PREINSTALL" ]] then - # Don't try to do a `git fetch` that may take longer than expected. - exit + FORCE_AUTO_UPDATE="$(git config homebrew.forceautoupdate 2>/dev/null || echo "false")" + if [[ "$FORCE_AUTO_UPDATE" != "true" ]] + then + # Don't try to do a `git fetch` that may take longer than expected. + exit + fi fi if [[ -n "$HOMEBREW_VERBOSE" ]] diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index 02bd489a43..340037a2ba 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -29,7 +29,7 @@ module Homebrew Homebrew.perform_preinstall_checks - odeprecated "'brew upgrade --all'", "'brew upgrade'" if ARGV.include?("--all") + odisabled "'brew upgrade --all'", "'brew upgrade'" if ARGV.include?("--all") if ARGV.named.empty? outdated = Formula.installed.select do |f| @@ -67,7 +67,14 @@ module Homebrew oh1 "No packages to upgrade" else oh1 "Upgrading #{Formatter.pluralize(formulae_to_install.length, "outdated package")}, with result:" - puts formulae_to_install.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", " + formulae_upgrades = formulae_to_install.map do |f| + if f.optlinked? + "#{f.full_specified_name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" + else + "#{f.full_specified_name} #{f.pkg_version}" + end + end + puts formulae_upgrades.join(", ") end # Sort keg_only before non-keg_only formulae to avoid any needless conflicts diff --git a/Library/Homebrew/cmd/uses.rb b/Library/Homebrew/cmd/uses.rb index 98ecca0f5d..bfc81f040a 100644 --- a/Library/Homebrew/cmd/uses.rb +++ b/Library/Homebrew/cmd/uses.rb @@ -54,48 +54,19 @@ module Homebrew used_formulae.all? do |ff| begin deps = f.runtime_dependencies if only_installed_arg - if recursive - deps ||= recursive_includes(Dependency, f, includes, ignores) - - dep_formulae = deps.flat_map do |dep| - begin - dep.to_formula - rescue - [] - end - end - - reqs_by_formula = ([f] + dep_formulae).flat_map do |formula| - formula.requirements.map { |req| [formula, req] } - end - - 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? - !includes.include?("build?") - end - end - - reqs = reqs_by_formula.map(&:last) + deps ||= if recursive + recursive_includes(Dependency, f, includes, ignores) else - deps ||= reject_ignores(f.deps, ignores, includes) - reqs = reject_ignores(f.requirements, ignores, includes) + reject_ignores(f.deps, ignores, includes) end - next true if deps.any? do |dep| + deps.any? do |dep| begin dep.to_formula.full_name == ff.full_name rescue dep.name == ff.name end end - - reqs.any? { |req| req.name == ff.name } rescue FormulaUnavailableError # Silently ignore this case as we don't care about things used in # taps that aren't currently tapped. diff --git a/Library/Homebrew/cmd/vendor-install.sh b/Library/Homebrew/cmd/vendor-install.sh index 8aba2174e5..909ff936a3 100644 --- a/Library/Homebrew/cmd/vendor-install.sh +++ b/Library/Homebrew/cmd/vendor-install.sh @@ -47,7 +47,15 @@ fetch() { local sha local temporary_path - curl_args=( + curl_args=() + + # do not load .curlrc unless requested (must be the first argument) + if [[ -z "$HOMEBREW_CURLRC" ]] + then + curl_args[${#curl_args[*]}]="-q" + fi + + curl_args+=( --fail --remote-time --location diff --git a/Library/Homebrew/compat.rb b/Library/Homebrew/compat.rb index a882f5a699..1f8d3871b9 100644 --- a/Library/Homebrew/compat.rb +++ b/Library/Homebrew/compat.rb @@ -1,32 +1,11 @@ -require "compat/fails_with_llvm" -require "compat/tap" require "compat/hbc" require "compat/formula" -require "compat/formula_specialties" require "compat/formula_support" -require "compat/global" -require "compat/hardware" -require "compat/macos" -require "compat/md5" -require "compat/sha1" require "compat/requirements" -require "compat/version" require "compat/download_strategy" -require "compat/keg" -require "compat/pathname" require "compat/dependency_collector" -require "compat/language/haskell" -require "compat/xcode" -require "compat/software_spec" -require "compat/utils" -require "compat/json" -require "compat/ARGV" -require "compat/build_options" -require "compat/tab" require "compat/ENV/shared" -require "compat/ENV/std" -require "compat/ENV/super" -require "compat/utils/shell" require "compat/extend/string" require "compat/gpg" require "compat/dependable" +require "compat/os/mac" diff --git a/Library/Homebrew/compat/ARGV.rb b/Library/Homebrew/compat/ARGV.rb deleted file mode 100644 index e56c4e01fd..0000000000 --- a/Library/Homebrew/compat/ARGV.rb +++ /dev/null @@ -1,5 +0,0 @@ -module HomebrewArgvExtension - def build_32_bit? - odisabled "ARGV.build_32_bit?" - end -end diff --git a/Library/Homebrew/compat/ENV/shared.rb b/Library/Homebrew/compat/ENV/shared.rb index 36ee456270..6bca25f9de 100644 --- a/Library/Homebrew/compat/ENV/shared.rb +++ b/Library/Homebrew/compat/ENV/shared.rb @@ -1,10 +1,9 @@ module SharedEnvExtension def j1 - odeprecated "ENV.j1", "ENV.deparallelize" - deparallelize + odisabled "ENV.j1", "ENV.deparallelize" end def java_cache - odeprecated "ENV.java_cache" + odisabled "ENV.java_cache" end end diff --git a/Library/Homebrew/compat/ENV/std.rb b/Library/Homebrew/compat/ENV/std.rb deleted file mode 100644 index beca4ed6f4..0000000000 --- a/Library/Homebrew/compat/ENV/std.rb +++ /dev/null @@ -1,25 +0,0 @@ -module Stdenv - def fast - odisabled "ENV.fast" - end - - def O4 - odisabled "ENV.O4" - end - - def Og - odisabled "ENV.Og" - end - - def gcc_4_0_1 - odisabled "ENV.gcc_4_0_1", "ENV.gcc_4_0" - end - - def gcc - odisabled "ENV.gcc", "ENV.gcc_4_2" - end - - def libpng - odisabled "ENV.libpng", "ENV.x11" - end -end diff --git a/Library/Homebrew/compat/ENV/super.rb b/Library/Homebrew/compat/ENV/super.rb deleted file mode 100644 index 53a6bdc4d6..0000000000 --- a/Library/Homebrew/compat/ENV/super.rb +++ /dev/null @@ -1,45 +0,0 @@ -module Superenv - def fast - odisabled "ENV.fast" - end - - def O4 - odisabled "ENV.O4" - end - - def Og - odisabled "ENV.Og" - end - - def gcc_4_0_1 - odisabled "ENV.gcc_4_0_1", "ENV.gcc_4_0" - end - - def gcc - odisabled "ENV.gcc", "ENV.gcc_4_2" - end - - def libxml2 - odisabled "ENV.libxml2" - end - - def minimal_optimization - odisabled "ENV.minimal_optimization" - end - - def no_optimization - odisabled "ENV.no_optimization" - end - - def enable_warnings - odisabled "ENV.enable_warnings" - end - - def macosxsdk - odisabled "ENV.macosxsdk" - end - - def remove_macosxsdk - odisabled "ENV.remove_macosxsdk" - end -end diff --git a/Library/Homebrew/compat/build_options.rb b/Library/Homebrew/compat/build_options.rb deleted file mode 100644 index 6e566a08c9..0000000000 --- a/Library/Homebrew/compat/build_options.rb +++ /dev/null @@ -1,9 +0,0 @@ -class BuildOptions - def build_32_bit? - odisabled "build.build_32_bit?" - end - - def build_bottle? - odisabled "build.build_bottle?", "build.bottle?" - end -end diff --git a/Library/Homebrew/compat/dependable.rb b/Library/Homebrew/compat/dependable.rb index faeeb9b183..1b7eec2f0c 100644 --- a/Library/Homebrew/compat/dependable.rb +++ b/Library/Homebrew/compat/dependable.rb @@ -1,5 +1,6 @@ module Dependable def run? + odeprecated "Dependable#run?" tags.include? :run end end diff --git a/Library/Homebrew/compat/dependency_collector.rb b/Library/Homebrew/compat/dependency_collector.rb index 9ee2b14035..685bbaf0ea 100644 --- a/Library/Homebrew/compat/dependency_collector.rb +++ b/Library/Homebrew/compat/dependency_collector.rb @@ -9,56 +9,42 @@ class DependencyCollector def parse_string_spec(spec, tags) if (tag = tags.first) && LANGUAGE_MODULES.include?(tag) - odeprecated "'depends_on ... => #{tag.inspect}'" - LanguageModuleRequirement.new(tag, spec, tags[1]) - else - super + odisabled "'depends_on ... => #{tag.inspect}'" end + + if tags.include?(:run) + odeprecated "'depends_on ... => :run'" + end + + super end def parse_symbol_spec(spec, tags) case spec when :clt - odeprecated "'depends_on :clt'" + odisabled "'depends_on :clt'" when :tex - odeprecated "'depends_on :tex'" - TeXRequirement.new(tags) - when :autoconf, :automake, :bsdmake, :libtool - output_deprecation(spec) - autotools_dep(spec, tags) - when :cairo, :fontconfig, :freetype, :libpng, :pixman - output_deprecation(spec) - Dependency.new(spec.to_s, tags) - when :ant, :expat - output_deprecation(spec) - Dependency.new(spec.to_s, tags) + odisabled "'depends_on :tex'" when :libltdl - output_deprecation("libtool") - Dependency.new("libtool", tags) + output_disabled(spec, "libtool") when :apr - output_deprecation(spec, "apr-util") - Dependency.new("apr-util", tags) + output_disabled(spec, "apr-util") when :fortran - output_deprecation(spec, "gcc") - Dependency.new("gcc", tags) + output_disabled(spec, "gcc") when :gpg - output_deprecation(spec, "gnupg") - Dependency.new("gnupg", tags) + output_disabled(spec, "gnupg") when :hg - output_deprecation(spec, "mercurial") - Dependency.new("mercurial", tags) + output_disabled(spec, "mercurial") when :mpi - output_deprecation(spec, "open-mpi") - Dependency.new("open-mpi", tags) + output_disabled(spec, "open-mpi") when :python, :python2 - output_deprecation(spec, "python@2") - Dependency.new("python@2", tags) + output_disabled(spec, "python@2") when :python3 - output_deprecation(spec, "python") - Dependency.new("python", tags) - when :emacs, :mysql, :perl, :postgresql, :rbenv, :ruby - output_deprecation(spec) - Dependency.new(spec.to_s, tags) + output_disabled(spec, "python") + when :ant, :autoconf, :automake, :bsdmake, :cairo, :emacs, :expat, + :fontconfig, :freetype, :libtool, :libpng, :mysql, :perl, :pixman, + :postgresql, :rbenv, :ruby + output_disabled(spec) else super end @@ -66,14 +52,9 @@ class DependencyCollector private - def autotools_dep(spec, tags) - tags << :build - Dependency.new(spec.to_s, tags) - end - - def output_deprecation(dependency, new_dependency = dependency) - odeprecated "'depends_on :#{dependency}'", - "'depends_on \"#{new_dependency}\"'" + def output_disabled(dependency, new_dependency = dependency) + odisabled "'depends_on :#{dependency}'", + "'depends_on \"#{new_dependency}\"'" end end diff --git a/Library/Homebrew/compat/extend/string.rb b/Library/Homebrew/compat/extend/string.rb index 9d1f665576..b704cd2b5f 100644 --- a/Library/Homebrew/compat/extend/string.rb +++ b/Library/Homebrew/compat/extend/string.rb @@ -1,7 +1,7 @@ class String def undent - odeprecated "<<-EOS.undent", "<<~EOS" - gsub(/^[ \t]{#{(slice(/^[ \t]+/) || '').length}}/, "") + odisabled "<<-EOS.undent", "<<~EOS" + self end alias unindent undent diff --git a/Library/Homebrew/compat/fails_with_llvm.rb b/Library/Homebrew/compat/fails_with_llvm.rb deleted file mode 100644 index 47bda4e0b3..0000000000 --- a/Library/Homebrew/compat/fails_with_llvm.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Formula - def fails_with_llvm(_msg = nil, _data = nil) - odisabled "Formula#fails_with_llvm in install" - end - - def self.fails_with_llvm(_msg = nil, _data = {}) - odisabled "Formula.fails_with_llvm" - end -end diff --git a/Library/Homebrew/compat/formula.rb b/Library/Homebrew/compat/formula.rb index 6f740710d8..397b8e12ca 100644 --- a/Library/Homebrew/compat/formula.rb +++ b/Library/Homebrew/compat/formula.rb @@ -1,74 +1,5 @@ -module FormulaCompat - def x11_installed? - odisabled "Formula#x11_installed?", "MacOS::X11.installed?" - end - - def snow_leopard_64? - odisabled "Formula#snow_leopard_64?", "MacOS.prefer_64_bit?" - end -end - class Formula - include FormulaCompat - extend FormulaCompat - - def std_cmake_parameters - odisabled "Formula#std_cmake_parameters", "Formula#std_cmake_args" - end - - def cxxstdlib_check(_) - odisabled "Formula#cxxstdlib_check in install", - "Formula.cxxstdlib_check outside install" - end - - def self.bottle_sha1(*) - odisabled "Formula.bottle_sha1" - end - - def self.all - odisabled "Formula.all", "Formula.map" - end - - def self.canonical_name(_) - odisabled "Formula.canonical_name", "Formulary.canonical_name" - end - - def self.class_s(_) - odisabled "Formula.class_s", "Formulary.class_s" - end - - def self.factory(_) - odisabled "Formula.factory", "Formulary.factory" - end - - def self.require_universal_deps - odisabled "Formula.require_universal_deps" - end - - def self.path(_) - odisabled "Formula.path", "Formulary.core_path" - end - - DATA = :DATA - - def patches - # Don't print deprecation warning because this method is inherited - # when used. - {} - end - - def python(_options = {}, &_) - odisabled "Formula#python" - end - alias python2 python - alias python3 python - - def startup_plist - odisabled "Formula#startup_plist", "Formula#plist" - end - - def rake(*args) - odeprecated "FileUtils#rake", "system \"rake\"" - system "rake", *args + def rake(*) + odisabled "FileUtils#rake", "system \"rake\"" end end diff --git a/Library/Homebrew/compat/formula_specialties.rb b/Library/Homebrew/compat/formula_specialties.rb deleted file mode 100644 index bc4d20beab..0000000000 --- a/Library/Homebrew/compat/formula_specialties.rb +++ /dev/null @@ -1,23 +0,0 @@ -class ScriptFileFormula < Formula - def install - odisabled "ScriptFileFormula#install", "Formula#install" - end -end - -class GithubGistFormula < ScriptFileFormula - def self.url(_val) - odisabled "GithubGistFormula.url", "Formula.url" - end -end - -class AmazonWebServicesFormula < Formula - def install - odisabled "AmazonWebServicesFormula#install", "Formula#install" - end - alias standard_install install - - # Use this method to generate standard caveats. - def standard_instructions(_, _) - odisabled "AmazonWebServicesFormula#standard_instructions", "Formula#caveats" - end -end diff --git a/Library/Homebrew/compat/formula_support.rb b/Library/Homebrew/compat/formula_support.rb index 9cb8d8ff14..81c37f313d 100644 --- a/Library/Homebrew/compat/formula_support.rb +++ b/Library/Homebrew/compat/formula_support.rb @@ -2,17 +2,80 @@ require "formula_support" class KegOnlyReason module Compat + def valid? + case @reason + when :provided_by_osx + odisabled "keg_only :provided_by_osx", "keg_only :provided_by_macos" + when :shadowed_by_osx + odisabled "keg_only :shadowed_by_osx", "keg_only :shadowed_by_macos" + when :provided_pre_mountain_lion + odeprecated "keg_only :provided_pre_mountain_lion" + MacOS.version < :mountain_lion + when :provided_pre_mavericks + odeprecated "keg_only :provided_pre_mavericks" + MacOS.version < :mavericks + when :provided_pre_el_capitan + odeprecated "keg_only :provided_pre_el_capitan" + MacOS.version < :el_capitan + when :provided_pre_high_sierra + odeprecated "keg_only :provided_pre_high_sierra" + MacOS.version < :high_sierra + when :provided_until_xcode43 + odeprecated "keg_only :provided_until_xcode43" + MacOS::Xcode.version < "4.3" + when :provided_until_xcode5 + odeprecated "keg_only :provided_until_xcode5" + MacOS::Xcode.version < "5.0" + else + super + end + end + def to_s case @reason when :provided_by_osx - odeprecated "keg_only :provided_by_osx", "keg_only :provided_by_macos" - @reason = :provided_by_macos + odisabled "keg_only :provided_by_osx", "keg_only :provided_by_macos" when :shadowed_by_osx - odeprecated "keg_only :shadowed_by_osx", "keg_only :shadowed_by_macos" - @reason = :shadowed_by_macos - end + odisabled "keg_only :shadowed_by_osx", "keg_only :shadowed_by_macos" + when :provided_pre_mountain_lion + odeprecated "keg_only :provided_pre_mountain_lion" - super + <<~EOS + macOS already provides this software in versions before Mountain Lion + EOS + when :provided_pre_mavericks + odeprecated "keg_only :provided_pre_mavericks" + + <<~EOS + macOS already provides this software in versions before Mavericks + EOS + when :provided_pre_el_capitan + odeprecated "keg_only :provided_pre_el_capitan" + + <<~EOS + macOS already provides this software in versions before El Capitan + EOS + when :provided_pre_high_sierra + odeprecated "keg_only :provided_pre_high_sierra" + + <<~EOS + macOS already provides this software in versions before High Sierra + EOS + when :provided_until_xcode43 + odeprecated "keg_only :provided_until_xcode43" + + <<~EOS + Xcode provides this software prior to version 4.3 + EOS + when :provided_until_xcode5 + odeprecated "keg_only :provided_until_xcode5" + + <<~EOS + Xcode provides this software prior to version 5 + EOS + else + super + end.to_s.strip end end diff --git a/Library/Homebrew/compat/global.rb b/Library/Homebrew/compat/global.rb deleted file mode 100644 index 9c8f0624cc..0000000000 --- a/Library/Homebrew/compat/global.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Homebrew - module_function - - def method_missing(method, *args, &block) - if instance_methods.include?(method) - odisabled "#{self}##{method}", "'module_function' or 'def self.#{method}' to convert it to a class method" - end - super - end - - def respond_to_missing?(method, include_private = false) - return true if method_defined?(method) - super(method, include_private) - end -end diff --git a/Library/Homebrew/compat/gpg.rb b/Library/Homebrew/compat/gpg.rb index e802d939cf..5aaecf4d31 100644 --- a/Library/Homebrew/compat/gpg.rb +++ b/Library/Homebrew/compat/gpg.rb @@ -1,27 +1,24 @@ -require "utils" module Gpg module_function def executable - odeprecated "Gpg.executable", 'which "gpg"' - which "gpg" + odisabled "Gpg.executable", 'which "gpg"' end def available? - odeprecated "Gpg.available?", 'which "gpg"' - File.executable?(executable.to_s) + odisabled "Gpg.available?", 'which "gpg"' end def create_test_key(_) - odeprecated "Gpg.create_test_key" + odisabled "Gpg.create_test_key" end def cleanup_test_processes! - odeprecated "Gpg.cleanup_test_processes!" + odisabled "Gpg.cleanup_test_processes!" end def test(_) - odeprecated "Gpg.test" + odisabled "Gpg.test" end end diff --git a/Library/Homebrew/compat/hardware.rb b/Library/Homebrew/compat/hardware.rb deleted file mode 100644 index 28bc79c60d..0000000000 --- a/Library/Homebrew/compat/hardware.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Hardware - class << self - def is_32_bit? - odisabled "Hardware.is_32_bit?", "Hardware::CPU.is_32_bit?" - end - - def is_64_bit? - odisabled "Hardware.is_64_bit?", "Hardware::CPU.is_64_bit?" - end - - def bits - odisabled "Hardware.bits", "Hardware::CPU.bits" - end - - def cpu_type - odisabled "Hardware.cpu_type", "Hardware::CPU.type" - end - - def cpu_family - odisabled "Hardware.cpu_family", "Hardware::CPU.family" - end - - def intel_family - odisabled "Hardware.intel_family", "Hardware::CPU.family" - end - - def ppc_family - odisabled "Hardware.ppc_family", "Hardware::CPU.family" - end - - def processor_count - odisabled "Hardware.processor_count", "Hardware::CPU.cores" - end - end -end diff --git a/Library/Homebrew/compat/json.rb b/Library/Homebrew/compat/json.rb deleted file mode 100644 index 18763b8a6e..0000000000 --- a/Library/Homebrew/compat/json.rb +++ /dev/null @@ -1,19 +0,0 @@ -require "json" - -module Utils - module JSON - module_function - - def load(_) - odisabled "Utils::JSON.load", "JSON.parse" - end - - def dump(_) - odisabled "Utils::JSON.dump", "JSON.generate" - end - - def stringify_keys(_) - odisabled "Utils::JSON.stringify_keys" - end - end -end diff --git a/Library/Homebrew/compat/keg.rb b/Library/Homebrew/compat/keg.rb deleted file mode 100644 index 81e1cf0b3f..0000000000 --- a/Library/Homebrew/compat/keg.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Keg - def fname - odisabled "Keg#fname", "Keg#name" - end -end diff --git a/Library/Homebrew/compat/language/haskell.rb b/Library/Homebrew/compat/language/haskell.rb deleted file mode 100644 index 8e50598743..0000000000 --- a/Library/Homebrew/compat/language/haskell.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Language - module Haskell - module Cabal - def cabal_clean_lib - odisabled "Language::Haskell::Cabal#cabal_clean_lib" - end - end - end -end diff --git a/Library/Homebrew/compat/macos.rb b/Library/Homebrew/compat/macos.rb deleted file mode 100644 index 879af83571..0000000000 --- a/Library/Homebrew/compat/macos.rb +++ /dev/null @@ -1,124 +0,0 @@ -require "development_tools" - -if OS.mac? - MACOS_FULL_VERSION = OS::Mac.full_version.to_s.freeze - MACOS_VERSION = OS::Mac.version.to_s.freeze -end - -module OS - module Mac - module_function - - def xcode_folder - odisabled "MacOS.xcode_folder", "MacOS::Xcode.folder" - end - - def xcode_prefix - odisabled "MacOS.xcode_prefix", "MacOS::Xcode.prefix" - end - - def xcode_installed? - odisabled "MacOS.xcode_installed?", "MacOS::Xcode.installed?" - end - - def xcode_version - odisabled "MacOS.xcode_version", "MacOS::Xcode.version" - end - - def clt_installed? - odisabled "MacOS.clt_installed?", "MacOS::CLT.installed?" - end - - def clt_version? - odisabled "MacOS.clt_version?", "MacOS::CLT.version" - end - - def x11_installed? - odisabled "MacOS.x11_installed?", "MacOS::X11.installed?" - end - - def x11_prefix - odisabled "MacOS.x11_prefix", "MacOS::X11.prefix" - end - - def leopard? - odisabled "MacOS.leopard?", "'MacOS.version == :leopard'" - end - - def snow_leopard? - odisabled "MacOS.snow_leopard?", "'MacOS.version >= :snow_leopard'" - end - - def snow_leopard_or_newer? - odisabled "MacOS.snow_leopard_or_newer?", "'MacOS.version >= :snow_leopard'" - end - - def lion? - odisabled "MacOS.lion?", "'MacOS.version >= :lion'" - end - - def lion_or_newer? - odisabled "MacOS.lion_or_newer?", "'MacOS.version >= :lion'" - end - - def mountain_lion? - odisabled "MacOS.mountain_lion?", "'MacOS.version >= :mountain_lion'" - end - - def mountain_lion_or_newer? - odisabled "MacOS.mountain_lion_or_newer?", "'MacOS.version >= :mountain_lion'" - end - - def macports_or_fink_installed? - odisabled "MacOS.macports_or_fink_installed?", "!MacOS.macports_or_fink.empty?" - end - - def locate(_) - odisabled "MacOS.locate", "DevelopmentTools.locate" - end - - def default_cc - odisabled "MacOS.default_cc", "DevelopmentTools.default_cc" - end - - def default_compiler - odisabled "MacOS.default_compiler", "DevelopmentTools.default_compiler" - end - - def gcc_40_build_version - odisabled "MacOS.gcc_40_build_version", "DevelopmentTools.gcc_4_0_build_version" - end - - def gcc_4_0_build_version - odisabled "MacOS.gcc_4_0_build_version", "DevelopmentTools.gcc_4_0_build_version" - end - - def gcc_42_build_version - odisabled "MacOS.gcc_42_build_version", "DevelopmentTools.gcc_4_2_build_version" - end - - def gcc_build_version - odisabled "MacOS.gcc_build_version", "DevelopmentTools.gcc_4_2_build_version" - end - - def llvm_build_version - odisabled "MacOS.llvm_build_version" - end - - def clang_version - odisabled "MacOS.clang_version", "DevelopmentTools.clang_version" - end - - def clang_build_version - odisabled "MacOS.clang_build_version", "DevelopmentTools.clang_build_version" - end - - def has_apple_developer_tools? - odisabled "MacOS.has_apple_developer_tools?", "DevelopmentTools.installed?" - end - - def release - odisabled "MacOS.release", "MacOS.version" - end - end -end diff --git a/Library/Homebrew/compat/md5.rb b/Library/Homebrew/compat/md5.rb deleted file mode 100644 index ede7edecb8..0000000000 --- a/Library/Homebrew/compat/md5.rb +++ /dev/null @@ -1,23 +0,0 @@ -class Formula - def self.md5(_val) - odisabled "Formula.md5", "Formula.sha256" - end -end - -class SoftwareSpec - def md5(_val) - odisabled "SoftwareSpec#md5", "SoftwareSpec#sha256" - end -end - -class Resource - def md5(_val) - odisabled "Resource#md5", "Resource#sha256" - end -end - -class Pathname - def md5 - odisabled "Pathname#md5", "Pathname#sha256" - end -end diff --git a/Library/Homebrew/compat/os/mac.rb b/Library/Homebrew/compat/os/mac.rb new file mode 100644 index 0000000000..6806fe900a --- /dev/null +++ b/Library/Homebrew/compat/os/mac.rb @@ -0,0 +1,10 @@ +module OS + module Mac + class << self + def release + odeprecated "MacOS.release", "MacOS.version" + version + end + end + end +end diff --git a/Library/Homebrew/compat/pathname.rb b/Library/Homebrew/compat/pathname.rb deleted file mode 100644 index df4b261a91..0000000000 --- a/Library/Homebrew/compat/pathname.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Pathname - def cp(_) - odisabled "Pathname#cp", "FileUtils.cp" - end - - def chmod_R(_) - odisabled "Pathname#chmod_R", "FileUtils.chmod_R" - end -end diff --git a/Library/Homebrew/compat/requirements.rb b/Library/Homebrew/compat/requirements.rb index 3dd5c74795..af0a9a25d0 100644 --- a/Library/Homebrew/compat/requirements.rb +++ b/Library/Homebrew/compat/requirements.rb @@ -1,123 +1,107 @@ require "requirements" -require "compat/requirements/language_module_requirement" class CVSRequirement < Requirement fatal true satisfy do - odeprecated("CVSRequirement", "'depends_on \"cvs\"'") - which "cvs" + odisabled("CVSRequirement", "'depends_on \"cvs\"'") end end class EmacsRequirement < Requirement fatal true satisfy do - odeprecated("EmacsRequirement", "'depends_on \"emacs\"'") - which "emacs" + odisabled("EmacsRequirement", "'depends_on \"emacs\"'") end end class FortranRequirement < Requirement fatal true satisfy do - odeprecated("FortranRequirement", "'depends_on \"gcc\"'") - which "gfortran" + odisabled("FortranRequirement", "'depends_on \"gcc\"'") end end class GitRequirement < Requirement fatal true satisfy do - odeprecated("GitRequirement", "'depends_on \"git\"'") - which "git" + odisabled("GitRequirement", "'depends_on \"git\"'") end end class GPG2Requirement < Requirement fatal true satisfy do - odeprecated("GPG2Requirement", "'depends_on \"gnupg\"'") - which "gpg" + odisabled("GPG2Requirement", "'depends_on \"gnupg\"'") end end class MercurialRequirement < Requirement fatal true satisfy do - odeprecated("MercurialRequirement", "'depends_on \"mercurial\"'") - which "hg" + odisabled("MercurialRequirement", "'depends_on \"mercurial\"'") end end class MPIRequirement < Requirement fatal true satisfy do - odeprecated("MPIRequirement", "'depends_on \"open-mpi\"'") - which "mpicc" + odisabled("MPIRequirement", "'depends_on \"open-mpi\"'") end end class MysqlRequirement < Requirement fatal true satisfy do - odeprecated("MysqlRequirement", "'depends_on \"mysql\"'") - which "mysql_config" + odisabled("MysqlRequirement", "'depends_on \"mysql\"'") end end class PerlRequirement < Requirement fatal true satisfy do - odeprecated("PerlRequirement", "'depends_on \"perl\"'") - which "perl" + odisabled("PerlRequirement", "'depends_on \"perl\"'") end end class PostgresqlRequirement < Requirement fatal true satisfy do - odeprecated("PostgresqlRequirement", "'depends_on \"postgresql\"'") - which "pg_config" + odisabled("PostgresqlRequirement", "'depends_on \"postgresql\"'") end end class PythonRequirement < Requirement fatal true satisfy do - odeprecated("PythonRequirement", "'depends_on \"python@2\"'") - which "python2" + odisabled("PythonRequirement", "'depends_on \"python@2\"'") end end class Python3Requirement < Requirement fatal true satisfy do - odeprecated("Python3Requirement", "'depends_on \"python\"'") - which "python" + odisabled("Python3Requirement", "'depends_on \"python\"'") end end class RbenvRequirement < Requirement fatal true satisfy do - odeprecated("RbenvRequirement", "'depends_on \"rbenv\"'") - which "rbenv" + odisabled("RbenvRequirement", "'depends_on \"rbenv\"'") end end class RubyRequirement < Requirement fatal true satisfy do - odeprecated("RubyRequirement", "'depends_on \"ruby\"'") - which "ruby" + odisabled("RubyRequirement", "'depends_on \"ruby\"'") end end class SubversionRequirement < Requirement fatal true satisfy do - odeprecated("SubversionRequirement", "'depends_on \"subversion\"'") - which "svn" + odisabled("SubversionRequirement", "'depends_on \"subversion\"'") end end @@ -126,8 +110,7 @@ class TeXRequirement < Requirement cask "mactex" download "https://www.tug.org/mactex/" satisfy do - odeprecated("TeXRequirement") - which("tex") || which("latex") + odisabled("TeXRequirement") end end diff --git a/Library/Homebrew/compat/requirements/language_module_requirement.rb b/Library/Homebrew/compat/requirements/language_module_requirement.rb deleted file mode 100644 index fc9dcc4428..0000000000 --- a/Library/Homebrew/compat/requirements/language_module_requirement.rb +++ /dev/null @@ -1,63 +0,0 @@ -require "requirement" - -class LanguageModuleRequirement < Requirement - fatal true - - def initialize(language, module_name, import_name = nil) - @language = language - @module_name = module_name - @import_name = import_name || module_name - super([language, module_name, import_name]) - end - - satisfy(build_env: false) { quiet_system(*the_test) } - - def message - s = <<~EOS - Unsatisfied dependency: #{@module_name} - Homebrew does not provide special #{@language.to_s.capitalize} dependencies; install with: - `#{command_line} #{@module_name}` - EOS - - unless [:python, :perl, :ruby].include? @language - s += <<~EOS - You may need to: `brew install #{@language}` - - EOS - end - - s - end - - def the_test - case @language - when :lua - ["/usr/bin/env", "luarocks-5.2", "show", @import_name.to_s] - when :lua51 - ["/usr/bin/env", "luarocks-5.1", "show", @import_name.to_s] - when :perl - ["/usr/bin/env", "perl", "-e", "use #{@import_name}"] - when :python - ["/usr/bin/env", "python2", "-c", "import #{@import_name}"] - when :python3 - ["/usr/bin/env", "python", "-c", "import #{@import_name}"] - when :ruby - ["/usr/bin/env", "ruby", "-rubygems", "-e", "require '#{@import_name}'"] - end - end - - def command_line - case @language - when :lua then "luarocks-5.2 install" - when :lua51 then "luarocks-5.1 install" - when :perl then "cpan -i" - when :python then "pip3 install" - when :python3 then "pip install" - when :ruby then "gem install" - end - end - - def display_s - "#{@module_name} (#{@language} module)" - end -end diff --git a/Library/Homebrew/compat/sha1.rb b/Library/Homebrew/compat/sha1.rb deleted file mode 100644 index adf11bdd5c..0000000000 --- a/Library/Homebrew/compat/sha1.rb +++ /dev/null @@ -1,29 +0,0 @@ -class Formula - def self.sha1(_val) - odisabled "Formula.sha1", "Formula.sha256" - end -end - -class SoftwareSpec - def sha1(_val) - odisabled "SoftwareSpec#sha1", "SoftwareSpec#sha256" - end -end - -class Resource - def sha1(_val) - odisabled "Resource#sha1", "Resource#sha256" - end -end - -class BottleSpecification - def sha1(_val) - odisabled "BottleSpecification#sha1", "BottleSpecification#sha256" - end -end - -class Pathname - def sha1 - odisabled "Pathname#sha1", "Pathname#sha256" - end -end diff --git a/Library/Homebrew/compat/software_spec.rb b/Library/Homebrew/compat/software_spec.rb deleted file mode 100644 index 814c00fa88..0000000000 --- a/Library/Homebrew/compat/software_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -class BottleSpecification - def revision(*) - odisabled "BottleSpecification.revision", "BottleSpecification.rebuild" - end -end diff --git a/Library/Homebrew/compat/tab.rb b/Library/Homebrew/compat/tab.rb deleted file mode 100644 index 651bcf1e19..0000000000 --- a/Library/Homebrew/compat/tab.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Tab < OpenStruct - def build_32_bit? - odisabled "Tab.build_32_bit?" - end -end diff --git a/Library/Homebrew/compat/tap.rb b/Library/Homebrew/compat/tap.rb deleted file mode 100644 index a1e3ce1727..0000000000 --- a/Library/Homebrew/compat/tap.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "tap" - -class Tap - def core_formula_repository? - odisabled "Tap#core_formula_repository?", "Tap#core_tap?" - end -end diff --git a/Library/Homebrew/compat/utils.rb b/Library/Homebrew/compat/utils.rb deleted file mode 100644 index f83d075998..0000000000 --- a/Library/Homebrew/compat/utils.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Tty - module_function - - def white - odisabled "Tty.white", "Tty.reset.bold" - end -end - -def puts_columns(_) - odisabled "puts_columns", "puts Formatter.columns" -end - -def plural(_, _) - odisabled "#plural", "Formatter.pluralize" -end diff --git a/Library/Homebrew/compat/utils/shell.rb b/Library/Homebrew/compat/utils/shell.rb deleted file mode 100644 index 2f387d967b..0000000000 --- a/Library/Homebrew/compat/utils/shell.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Utils - module Shell - def self.shell_profile - odisabled "Utils::Shell.shell_profile", "Utils::Shell.profile" - end - end -end diff --git a/Library/Homebrew/compat/version.rb b/Library/Homebrew/compat/version.rb deleted file mode 100644 index 4a6fd7ace5..0000000000 --- a/Library/Homebrew/compat/version.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Version - def slice(*) - odisabled "Version#slice", "Version#to_s.slice" - end -end diff --git a/Library/Homebrew/compat/xcode.rb b/Library/Homebrew/compat/xcode.rb deleted file mode 100644 index f212ada641..0000000000 --- a/Library/Homebrew/compat/xcode.rb +++ /dev/null @@ -1,11 +0,0 @@ -module OS - module Mac - module Xcode - module_function - - def provides_autotools? - odisabled "OS::Mac::Xcode.provides_autotools?" - end - end - end -end diff --git a/Library/Homebrew/config.rb b/Library/Homebrew/config.rb index 30b7bc6c9c..38d7c80438 100644 --- a/Library/Homebrew/config.rb +++ b/Library/Homebrew/config.rb @@ -2,8 +2,6 @@ unless ENV["HOMEBREW_BREW_FILE"] raise "HOMEBREW_BREW_FILE was not exported! Please call bin/brew directly!" end -require "constants" - # Path to `bin/brew` main executable in HOMEBREW_PREFIX HOMEBREW_BREW_FILE = Pathname.new(ENV["HOMEBREW_BREW_FILE"]) diff --git a/Library/Homebrew/constants.rb b/Library/Homebrew/constants.rb index 3d2a1d0f39..25326075e5 100644 --- a/Library/Homebrew/constants.rb +++ b/Library/Homebrew/constants.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true # RuboCop version used for `brew style` and `brew cask style` -HOMEBREW_RUBOCOP_VERSION = "0.54.0" -HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.18.0" # has to be updated when RuboCop version changes +HOMEBREW_RUBOCOP_VERSION = "0.55.0" +HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.19.0" # has to be updated when RuboCop version changes diff --git a/Library/Homebrew/dependency_collector.rb b/Library/Homebrew/dependency_collector.rb index 74f42a6aaf..1a00c72012 100644 --- a/Library/Homebrew/dependency_collector.rb +++ b/Library/Homebrew/dependency_collector.rb @@ -2,7 +2,6 @@ require "dependency" require "dependencies" require "requirement" require "requirements" -require "set" require "extend/cachable" ## A dependency is a formula that another formula needs to install. diff --git a/Library/Homebrew/descriptions.rb b/Library/Homebrew/descriptions.rb index bc19826731..4db47e77f1 100644 --- a/Library/Homebrew/descriptions.rb +++ b/Library/Homebrew/descriptions.rb @@ -1,4 +1,3 @@ -require "set" require "formula" require "formula_versions" diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 5eaffe2afa..45c9561c62 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -39,11 +39,9 @@ require "formula" require "formula_versions" -require "utils" require "utils/curl" require "extend/ENV" require "formula_cellar_checks" -require "official_taps" require "cmd/search" require "cmd/style" require "date" @@ -141,826 +139,834 @@ module Homebrew ofail "#{Formatter.pluralize(problem_count, "problem")} in #{Formatter.pluralize(formula_count, "formula")}" end -end -class FormulaText - def initialize(path) - @text = path.open("rb", &:read) - @lines = @text.lines.to_a - end + class FormulaText + def initialize(path) + @text = path.open("rb", &:read) + @lines = @text.lines.to_a + end - def without_patch - @text.split("\n__END__").first - end + def without_patch + @text.split("\n__END__").first + end - def data? - /^[^#]*\bDATA\b/ =~ @text - end + def data? + /^[^#]*\bDATA\b/ =~ @text + end - def end? - /^__END__$/ =~ @text - end + def end? + /^__END__$/ =~ @text + end - def trailing_newline? - /\Z\n/ =~ @text - end + def trailing_newline? + /\Z\n/ =~ @text + end - def =~(other) - other =~ @text - end + def =~(other) + other =~ @text + end - def include?(s) - @text.include? s - end + def include?(s) + @text.include? s + end - def line_number(regex, skip = 0) - index = @lines.drop(skip).index { |line| line =~ regex } - index ? index + 1 : nil - end + def line_number(regex, skip = 0) + index = @lines.drop(skip).index { |line| line =~ regex } + index ? index + 1 : nil + end - def reverse_line_number(regex) - index = @lines.reverse.index { |line| line =~ regex } - index ? @lines.count - index : nil - end -end - -class FormulaAuditor - include FormulaCellarChecks - - attr_reader :formula, :text, :problems - - 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 - @official_tap = formula.tap&.official? || options[:official_tap] - @problems = [] - @text = FormulaText.new(formula.path) - @specs = %w[stable devel head].map { |s| formula.send(s) }.compact - end - - def audit_style - return unless @style_offenses - @style_offenses.each do |offense| - problem offense.to_s(display_cop_name: @display_cop_names) + def reverse_line_number(regex) + index = @lines.reverse.index { |line| line =~ regex } + index ? @lines.count - index : nil end end - def audit_file - # Under normal circumstances (umask 0022), we expect a file mode of 644. If - # the user's umask is more restrictive, respect that by masking out the - # corresponding bits. (The also included 0100000 flag means regular file.) - wanted_mode = 0100644 & ~File.umask - actual_mode = formula.path.stat.mode - unless actual_mode == wanted_mode - problem format("Incorrect file permissions (%03o): chmod %03o %s", - actual_mode & 0777, wanted_mode & 0777, formula.path) + class FormulaAuditor + include FormulaCellarChecks + + attr_reader :formula, :text, :problems + + 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 + @official_tap = formula.tap&.official? || options[:official_tap] + @problems = [] + @text = FormulaText.new(formula.path) + @specs = %w[stable devel head].map { |s| formula.send(s) }.compact end - problem "'DATA' was found, but no '__END__'" if text.data? && !text.end? - - if text.end? && !text.data? - problem "'__END__' was found, but 'DATA' is not used" + def audit_style + return unless @style_offenses + @style_offenses.each do |offense| + problem offense.to_s(display_cop_name: @display_cop_names) + end end - if text =~ /inreplace [^\n]* do [^\n]*\n[^\n]*\.gsub![^\n]*\n\ *end/m - problem "'inreplace ... do' was used for a single substitution (use the non-block form instead)." - end + def audit_file + # Under normal circumstances (umask 0022), we expect a file mode of 644. If + # the user's umask is more restrictive, respect that by masking out the + # corresponding bits. (The also included 0100000 flag means regular file.) + wanted_mode = 0100644 & ~File.umask + actual_mode = formula.path.stat.mode + unless actual_mode == wanted_mode + problem format("Incorrect file permissions (%03o): chmod %03o %s", + actual_mode & 0777, wanted_mode & 0777, formula.path) + end - problem "File should end with a newline" unless text.trailing_newline? + problem "'DATA' was found, but no '__END__'" if text.data? && !text.end? - if formula.versioned_formula? - unversioned_formula = begin - # build this ourselves as we want e.g. homebrew/core to be present - full_name = if formula.tap - "#{formula.tap}/#{formula.name}" - else - formula.name + if text.end? && !text.data? + problem "'__END__' was found, but 'DATA' is not used" + end + + if text =~ /inreplace [^\n]* do [^\n]*\n[^\n]*\.gsub![^\n]*\n\ *end/m + problem "'inreplace ... do' was used for a single substitution (use the non-block form instead)." + end + + problem "File should end with a newline" unless text.trailing_newline? + + if formula.versioned_formula? + unversioned_formula = begin + # build this ourselves as we want e.g. homebrew/core to be present + full_name = if formula.tap + "#{formula.tap}/#{formula.name}" + else + formula.name + end + Formulary.factory(full_name.gsub(/@.*$/, "")).path + rescue FormulaUnavailableError, TapFormulaAmbiguityError, + TapFormulaWithOldnameAmbiguityError + Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb") end - Formulary.factory(full_name.gsub(/@.*$/, "")).path - rescue FormulaUnavailableError, TapFormulaAmbiguityError, - TapFormulaWithOldnameAmbiguityError - Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb") - end - unless unversioned_formula.exist? - unversioned_name = unversioned_formula.basename(".rb") - problem "#{formula} is versioned but no #{unversioned_name} formula exists" - end - elsif ARGV.build_stable? && formula.stable? && - !(versioned_formulae = Dir[formula.path.to_s.gsub(/\.rb$/, "@*.rb")]).empty? - versioned_aliases = formula.aliases.grep(/.@\d/) - _, last_alias_version = - File.basename(versioned_formulae.sort.reverse.first) - .gsub(/\.rb$/, "").split("@") - major, minor, = formula.version.to_s.split(".") - alias_name_major = "#{formula.name}@#{major}" - alias_name_major_minor = "#{alias_name_major}.#{minor}" - alias_name = if last_alias_version.split(".").length == 1 - alias_name_major - else - alias_name_major_minor - end - valid_alias_names = [alias_name_major, alias_name_major_minor] + unless unversioned_formula.exist? + unversioned_name = unversioned_formula.basename(".rb") + problem "#{formula} is versioned but no #{unversioned_name} formula exists" + end + elsif ARGV.build_stable? && formula.stable? && + !(versioned_formulae = Dir[formula.path.to_s.gsub(/\.rb$/, "@*.rb")]).empty? + versioned_aliases = formula.aliases.grep(/.@\d/) + _, last_alias_version = + File.basename(versioned_formulae.sort.reverse.first) + .gsub(/\.rb$/, "").split("@") + major, minor, = formula.version.to_s.split(".") + alias_name_major = "#{formula.name}@#{major}" + alias_name_major_minor = "#{alias_name_major}.#{minor}" + alias_name = if last_alias_version.split(".").length == 1 + alias_name_major + else + alias_name_major_minor + end + valid_alias_names = [alias_name_major, alias_name_major_minor] - unless formula.tap&.core_tap? - versioned_aliases.map! { |a| "#{formula.tap}/#{a}" } - valid_alias_names.map! { |a| "#{formula.tap}/#{a}" } - end + unless formula.tap&.core_tap? + versioned_aliases.map! { |a| "#{formula.tap}/#{a}" } + valid_alias_names.map! { |a| "#{formula.tap}/#{a}" } + end - valid_versioned_aliases = versioned_aliases & valid_alias_names - invalid_versioned_aliases = versioned_aliases - valid_alias_names + valid_versioned_aliases = versioned_aliases & valid_alias_names + invalid_versioned_aliases = versioned_aliases - valid_alias_names - if valid_versioned_aliases.empty? - if formula.tap + if valid_versioned_aliases.empty? + if formula.tap + problem <<~EOS + Formula has other versions so create a versioned alias: + cd #{formula.tap.alias_dir} + ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name} + EOS + else + problem "Formula has other versions so create an alias named #{alias_name}." + end + end + + unless invalid_versioned_aliases.empty? problem <<~EOS - Formula has other versions so create a versioned alias: - cd #{formula.tap.alias_dir} - ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name} + Formula has invalid versioned aliases: + #{invalid_versioned_aliases.join("\n ")} EOS - else - problem "Formula has other versions so create an alias named #{alias_name}." end end + end - unless invalid_versioned_aliases.empty? - problem <<~EOS - Formula has invalid versioned aliases: - #{invalid_versioned_aliases.join("\n ")} - EOS + def self.aliases + # core aliases + tap alias names + tap alias full name + @aliases ||= Formula.aliases + Formula.tap_aliases + end + + def audit_formula_name + return unless @strict + # skip for non-official taps + return unless @official_tap + + name = formula.name + + if MissingFormula.blacklisted_reason(name) + problem "'#{name}' is blacklisted." end - end - end - def self.aliases - # core aliases + tap alias names + tap alias full name - @aliases ||= Formula.aliases + Formula.tap_aliases - end + if Formula.aliases.include? name + problem "Formula name conflicts with existing aliases." + return + end - def audit_formula_name - return unless @strict - # skip for non-official taps - return unless @official_tap + if oldname = CoreTap.instance.formula_renames[name] + problem "'#{name}' is reserved as the old name of #{oldname}" + return + end - name = formula.name + return if formula.core_formula? + return unless Formula.core_names.include?(name) - if Homebrew::MissingFormula.blacklisted_reason(name) - problem "'#{name}' is blacklisted." + problem "Formula name conflicts with existing core formula." end - if Formula.aliases.include? name - problem "Formula name conflicts with existing aliases." - return - end - - if oldname = CoreTap.instance.formula_renames[name] - problem "'#{name}' is reserved as the old name of #{oldname}" - return - end - - return if formula.core_formula? - return unless Formula.core_names.include?(name) - - problem "Formula name conflicts with existing core formula." - end - - def audit_deps - @specs.each do |spec| - # Check for things we don't like to depend on. - # We allow non-Homebrew installs whenever possible. - spec.deps.each do |dep| - begin - dep_f = dep.to_formula - rescue TapFormulaUnavailableError - # Don't complain about missing cross-tap dependencies - next - rescue FormulaUnavailableError - problem "Can't find dependency #{dep.name.inspect}." - next - rescue TapFormulaAmbiguityError - problem "Ambiguous dependency #{dep.name.inspect}." - next - rescue TapFormulaWithOldnameAmbiguityError - problem "Ambiguous oldname dependency #{dep.name.inspect}." - next - end - - if dep_f.oldname && dep.name.split("/").last == dep_f.oldname - problem "Dependency '#{dep.name}' was renamed; use new name '#{dep_f.name}'." - end - - if self.class.aliases.include?(dep.name) && - (dep_f.core_formula? || !dep_f.versioned_formula?) - problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'." - end - - if @new_formula && dep_f.keg_only_reason && - !["openssl", "apr", "apr-util"].include?(dep.name) && - [:provided_by_macos, :provided_by_osx].include?(dep_f.keg_only_reason.reason) - problem "Dependency '#{dep.name}' may be unnecessary as it is provided by macOS; try to build this formula without it." - end - - dep.options.each do |opt| - next if dep_f.option_defined?(opt) - next if dep_f.requirements.detect do |r| - if r.recommended? - opt.name == "with-#{r.name}" - elsif r.optional? - opt.name == "without-#{r.name}" - end + def audit_deps + @specs.each do |spec| + # Check for things we don't like to depend on. + # We allow non-Homebrew installs whenever possible. + spec.deps.each do |dep| + begin + dep_f = dep.to_formula + rescue TapFormulaUnavailableError + # Don't complain about missing cross-tap dependencies + next + rescue FormulaUnavailableError + problem "Can't find dependency #{dep.name.inspect}." + next + rescue TapFormulaAmbiguityError + problem "Ambiguous dependency #{dep.name.inspect}." + next + rescue TapFormulaWithOldnameAmbiguityError + problem "Ambiguous oldname dependency #{dep.name.inspect}." + next end - problem "Dependency #{dep} does not define option #{opt.name.inspect}" - end + if dep_f.oldname && dep.name.split("/").last == dep_f.oldname + problem "Dependency '#{dep.name}' was renamed; use new name '#{dep_f.name}'." + end - if dep.name == "git" - problem "Don't use git as a dependency (it's always available)" - end + if self.class.aliases.include?(dep.name) && + (dep_f.core_formula? || !dep_f.versioned_formula?) + problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'." + end - if dep.tags.include?(:run) - problem "Dependency '#{dep.name}' is marked as :run. Remove :run; it is a no-op." + if @new_formula && dep_f.keg_only_reason && + !["openssl", "apr", "apr-util"].include?(dep.name) && + [:provided_by_macos, :provided_by_osx].include?(dep_f.keg_only_reason.reason) + problem "Dependency '#{dep.name}' may be unnecessary as it is provided by macOS; try to build this formula without it." + end + + dep.options.each do |opt| + next if dep_f.option_defined?(opt) + next if dep_f.requirements.detect do |r| + if r.recommended? + opt.name == "with-#{r.name}" + elsif r.optional? + opt.name == "without-#{r.name}" + end + end + + problem "Dependency #{dep} does not define option #{opt.name.inspect}" + end + + if dep.name == "git" + problem "Don't use git as a dependency (it's always available)" + end + + if dep.tags.include?(:run) + problem "Dependency '#{dep.name}' is marked as :run. Remove :run; it is a no-op." + end end end end - end - def audit_conflicts - formula.conflicts.each do |c| + def audit_conflicts + formula.conflicts.each do |c| + begin + Formulary.factory(c.name) + rescue TapFormulaUnavailableError + # Don't complain about missing cross-tap conflicts. + next + rescue FormulaUnavailableError + problem "Can't find conflicting formula #{c.name.inspect}." + rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError + problem "Ambiguous conflicting formula #{c.name.inspect}." + end + end + end + + def audit_keg_only_style + return unless @strict + return unless formula.keg_only? + + whitelist = %w[ + Apple + macOS + OS + Homebrew + Xcode + GPG + GNOME + BSD + Firefox + ].freeze + + reason = formula.keg_only_reason.to_s + # Formulae names can legitimately be uppercase/lowercase/both. + name = Regexp.new(formula.name, Regexp::IGNORECASE) + reason.sub!(name, "") + first_word = reason.split[0] + + if reason =~ /\A[A-Z]/ && !reason.start_with?(*whitelist) + problem <<~EOS + '#{first_word}' from the keg_only reason should be '#{first_word.downcase}'. + EOS + end + + return unless reason.end_with?(".") + problem "keg_only reason should not end with a period." + end + + def audit_homepage + homepage = formula.homepage + + return if homepage.nil? || homepage.empty? + + return unless @online + + return unless DevelopmentTools.curl_handles_most_https_certificates? + if http_content_problem = curl_check_http_content(homepage, + user_agents: [:browser, :default], + check_content: true, + strict: @strict) + problem http_content_problem + end + end + + def audit_bottle_spec + return unless formula.bottle_disabled? + return if formula.bottle_disable_reason.valid? + problem "Unrecognized bottle modifier" + end + + def audit_github_repository + return unless @online + return unless @new_formula + + regex = %r{https?://github\.com/([^/]+)/([^/]+)/?.*} + _, user, repo = *regex.match(formula.stable.url) if formula.stable + _, user, repo = *regex.match(formula.homepage) unless user + return if !user || !repo + + repo.gsub!(/.git$/, "") + begin - Formulary.factory(c.name) - rescue TapFormulaUnavailableError - # Don't complain about missing cross-tap conflicts. - next - rescue FormulaUnavailableError - problem "Can't find conflicting formula #{c.name.inspect}." - rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError - problem "Ambiguous conflicting formula #{c.name.inspect}." + metadata = GitHub.repository(user, repo) + rescue GitHub::HTTPNotFoundError + return + end + + return if metadata.nil? + + problem "GitHub fork (not canonical repository)" if metadata["fork"] + if formula&.tap&.core_tap? && + (metadata["forks_count"] < 20) && (metadata["subscribers_count"] < 20) && + (metadata["stargazers_count"] < 50) + problem "GitHub repository not notable enough (<20 forks, <20 watchers and <50 stars)" + end + + return if Date.parse(metadata["created_at"]) <= (Date.today - 30) + problem "GitHub repository too new (<30 days old)" + end + + def audit_specs + if head_only?(formula) && formula.tap.to_s.downcase !~ %r{[-/]head-only$} + problem "Head-only (no stable download)" + end + + if devel_only?(formula) && formula.tap.to_s.downcase !~ %r{[-/]devel-only$} + problem "Devel-only (no stable download)" + end + + %w[Stable Devel HEAD].each do |name| + spec_name = name.downcase.to_sym + next unless spec = formula.send(spec_name) + + ra = ResourceAuditor.new(spec, spec_name, online: @online, strict: @strict).audit + problems.concat ra.problems.map { |problem| "#{name}: #{problem}" } + + spec.resources.each_value do |resource| + ra = ResourceAuditor.new(resource, spec_name, online: @online, strict: @strict).audit + problems.concat ra.problems.map { |problem| + "#{name} resource #{resource.name.inspect}: #{problem}" + } + end + + next if spec.patches.empty? + next unless @new_formula + problem "New formulae should not require patches to build. Patches should be submitted and accepted upstream first." + end + + %w[Stable Devel].each do |name| + next unless spec = formula.send(name.downcase) + version = spec.version + if version.to_s !~ /\d/ + problem "#{name}: version (#{version}) is set to a string without a digit" + end + if version.to_s.start_with?("HEAD") + problem "#{name}: non-HEAD version name (#{version}) should not begin with HEAD" + end + end + + if formula.stable && formula.devel + if formula.devel.version < formula.stable.version + problem "devel version #{formula.devel.version} is older than stable version #{formula.stable.version}" + elsif formula.devel.version == formula.stable.version + problem "stable and devel versions are identical" + end + end + + if @new_formula && formula.head + problem "New formulae should not have a HEAD spec" + end + + unstable_whitelist = %w[ + aalib 1.4rc5 + angolmois 2.0.0alpha2 + automysqlbackup 3.0-rc6 + aview 1.3.0rc1 + distcc 3.2rc1 + elm-format 0.6.0-alpha + ftgl 2.1.3-rc5 + hidapi 0.8.0-rc1 + libcaca 0.99b19 + nethack4 4.3.0-beta2 + opensyobon 1.0rc2 + premake 4.4-beta5 + pwnat 0.3-beta + pxz 4.999.9 + recode 3.7-beta2 + speexdsp 1.2rc3 + sqoop 1.4.6 + tcptraceroute 1.5beta7 + testssl 2.8rc3 + tiny-fugue 5.0b8 + vbindiff 3.0_beta4 + ].each_slice(2).to_a.map do |formula, version| + [formula, version.sub(/\d+$/, "")] + end + + gnome_devel_whitelist = %w[ + 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 + + stable = formula.stable + case stable&.url + when /[\d\._-](alpha|beta|rc\d)/ + matched = Regexp.last_match(1) + version_prefix = stable.version.to_s.sub(/\d+$/, "") + return if unstable_whitelist.include?([formula.name, version_prefix]) + problem "Stable version URLs should not contain #{matched}" + when %r{download\.gnome\.org/sources}, %r{ftp\.gnome\.org/pub/GNOME/sources}i + version_prefix = stable.version.to_s.split(".")[0..1].join(".") + return if gnome_devel_whitelist.include?([formula.name, version_prefix]) + version = Version.parse(stable.url) + if version >= Version.create("1.0") + minor_version = version.to_s.split(".", 3)[1].to_i + if minor_version.odd? + problem "#{stable.version} is a development release" + end + end end end - end - def audit_keg_only_style - return unless @strict - return unless formula.keg_only? + def audit_revision_and_version_scheme + return unless formula.tap # skip formula not from core or any taps + return unless formula.tap.git? # git log is required + return if @new_formula - whitelist = %w[ - Apple - macOS - OS - Homebrew - Xcode - GPG - GNOME - BSD - Firefox - ].freeze + fv = FormulaVersions.new(formula) - reason = formula.keg_only_reason.to_s - # Formulae names can legitimately be uppercase/lowercase/both. - name = Regexp.new(formula.name, Regexp::IGNORECASE) - reason.sub!(name, "") - first_word = reason.split[0] + previous_version_and_checksum = fv.previous_version_and_checksum("origin/master") + [:stable, :devel].each do |spec_sym| + next unless spec = formula.send(spec_sym) + next unless previous_version_and_checksum[spec_sym][:version] == spec.version + next if previous_version_and_checksum[spec_sym][:checksum] == spec.checksum + problem "#{spec_sym}: sha256 changed without the version also changing; please create an issue upstream to rule out malicious circumstances and to find out why the file changed." + end + + attributes = [:revision, :version_scheme] + attributes_map = fv.version_attributes_map(attributes, "origin/master") + + current_version_scheme = formula.version_scheme + [:stable, :devel].each do |spec| + spec_version_scheme_map = attributes_map[:version_scheme][spec] + next if spec_version_scheme_map.empty? + + version_schemes = spec_version_scheme_map.values.flatten + max_version_scheme = version_schemes.max + max_version = spec_version_scheme_map.select do |_, version_scheme| + version_scheme.first == max_version_scheme + end.keys.max + + if max_version_scheme && current_version_scheme < max_version_scheme + problem "version_scheme should not decrease (from #{max_version_scheme} to #{current_version_scheme})" + end + + if max_version_scheme && current_version_scheme >= max_version_scheme && + current_version_scheme > 1 && + !version_schemes.include?(current_version_scheme - 1) + problem "version_schemes should only increment by 1" + end + + formula_spec = formula.send(spec) + next unless formula_spec + + spec_version = formula_spec.version + next unless max_version + next if spec_version >= max_version + + above_max_version_scheme = current_version_scheme > max_version_scheme + map_includes_version = spec_version_scheme_map.keys.include?(spec_version) + next if !current_version_scheme.zero? && + (above_max_version_scheme || map_includes_version) + problem "#{spec} version should not decrease (from #{max_version} to #{spec_version})" + end + + current_revision = formula.revision + revision_map = attributes_map[:revision][:stable] + if formula.stable && !revision_map.empty? + stable_revisions = revision_map[formula.stable.version] + stable_revisions ||= [] + max_revision = stable_revisions.max || 0 + + if current_revision < max_revision + problem "revision should not decrease (from #{max_revision} to #{current_revision})" + end + + stable_revisions -= [formula.revision] + if !current_revision.zero? && stable_revisions.empty? && + revision_map.keys.length > 1 + problem "'revision #{formula.revision}' should be removed" + elsif current_revision > 1 && + current_revision != max_revision && + !stable_revisions.include?(current_revision - 1) + problem "revisions should only increment by 1" + end + elsif !current_revision.zero? # head/devel-only formula + problem "'revision #{current_revision}' should be removed" + end + end + + def audit_text + bin_names = Set.new + bin_names << formula.name + bin_names += formula.aliases + [formula.bin, formula.sbin].each do |dir| + next unless dir.exist? + bin_names += dir.children.map(&:basename).map(&:to_s) + end + bin_names.each do |name| + ["system", "shell_output", "pipe_output"].each do |cmd| + if text =~ %r{(def test|test do).*(#{Regexp.escape(HOMEBREW_PREFIX)}/bin/)?#{cmd}[\(\s]+['"]#{Regexp.escape(name)}[\s'"]}m + problem %Q(fully scope test #{cmd} calls e.g. #{cmd} "\#{bin}/#{name}") + end + end + end + end + + def audit_lines + text.without_patch.split("\n").each_with_index do |line, lineno| + line_problems(line, lineno + 1) + end + end + + def line_problems(line, _lineno) + # Check for string interpolation of single values. + if line =~ /(system|inreplace|gsub!|change_make_var!).*[ ,]"#\{([\w.]+)\}"/ + problem "Don't need to interpolate \"#{Regexp.last_match(2)}\" with #{Regexp.last_match(1)}" + end + + # Check for string concatenation; prefer interpolation + if line =~ /(#\{\w+\s*\+\s*['"][^}]+\})/ + problem "Try not to concatenate paths in string interpolation:\n #{Regexp.last_match(1)}" + end + + # Prefer formula path shortcuts in Pathname+ + if line =~ %r{\(\s*(prefix\s*\+\s*(['"])(bin|include|libexec|lib|sbin|share|Frameworks)[/'"])} + problem "\"(#{Regexp.last_match(1)}...#{Regexp.last_match(2)})\" should be \"(#{Regexp.last_match(3).downcase}+...)\"" + end + + problem "Use separate make calls" if line.include?("make && make") + + if line =~ /JAVA_HOME/i && !formula.requirements.map(&:class).include?(JavaRequirement) + problem "Use `depends_on :java` to set JAVA_HOME" + end + + return unless @strict + + if @official_tap && line.include?("env :std") + problem "`env :std` in official tap formulae is deprecated" + end + + if line.include?("env :userpaths") + problem "`env :userpaths` in formulae is deprecated" + end + + if line =~ /system ((["'])[^"' ]*(?:\s[^"' ]*)+\2)/ + bad_system = Regexp.last_match(1) + unless %w[| < > & ; *].any? { |c| bad_system.include? c } + good_system = bad_system.gsub(" ", "\", \"") + problem "Use `system #{good_system}` instead of `system #{bad_system}` " + end + end + + problem "`#{Regexp.last_match(1)}` is now unnecessary" if line =~ /(require ["']formula["'])/ + + if line =~ %r{#\{share\}/#{Regexp.escape(formula.name)}[/'"]} + problem "Use \#{pkgshare} instead of \#{share}/#{formula.name}" + end + + if line =~ /depends_on .+ if build\.with(out)?\?\(?["']\w+["']\)?/ + problem "`Use :optional` or `:recommended` instead of `#{Regexp.last_match(0)}`" + end + + return unless line =~ %r{share(\s*[/+]\s*)(['"])#{Regexp.escape(formula.name)}(?:\2|/)} + problem "Use pkgshare instead of (share#{Regexp.last_match(1)}\"#{formula.name}\")" + end + + def audit_reverse_migration + # Only enforce for new formula being re-added to core and official taps + return unless @strict + return unless @official_tap + return unless formula.tap.tap_migrations.key?(formula.name) - if reason =~ /\A[A-Z]/ && !reason.start_with?(*whitelist) problem <<~EOS - '#{first_word}' from the keg_only reason should be '#{first_word.downcase}'. + #{formula.name} seems to be listed in tap_migrations.json! + Please remove #{formula.name} from present tap & tap_migrations.json + before submitting it to Homebrew/homebrew-#{formula.tap.repo}. EOS end - return unless reason.end_with?(".") - problem "keg_only reason should not end with a period." - end + def audit_prefix_has_contents + return unless formula.prefix.directory? + return unless Keg.new(formula.prefix).empty_installation? - def audit_homepage - homepage = formula.homepage - - return if homepage.nil? || homepage.empty? - - return unless @online - - return unless DevelopmentTools.curl_handles_most_https_certificates? - if http_content_problem = curl_check_http_content(homepage, - user_agents: [:browser, :default], - check_content: true, - strict: @strict) - problem http_content_problem - end - end - - def audit_bottle_spec - return unless formula.bottle_disabled? - return if formula.bottle_disable_reason.valid? - problem "Unrecognized bottle modifier" - end - - def audit_github_repository - return unless @online - return unless @new_formula - - regex = %r{https?://github\.com/([^/]+)/([^/]+)/?.*} - _, user, repo = *regex.match(formula.stable.url) if formula.stable - _, user, repo = *regex.match(formula.homepage) unless user - return if !user || !repo - - repo.gsub!(/.git$/, "") - - begin - metadata = GitHub.repository(user, repo) - rescue GitHub::HTTPNotFoundError - return + problem <<~EOS + The installation seems to be empty. Please ensure the prefix + is set correctly and expected files are installed. + The prefix configure/make argument may be case-sensitive. + EOS end - return if metadata.nil? + def audit_url_is_not_binary + return unless @official_tap - problem "GitHub fork (not canonical repository)" if metadata["fork"] - if formula&.tap&.core_tap? && - (metadata["forks_count"] < 20) && (metadata["subscribers_count"] < 20) && - (metadata["stargazers_count"] < 50) - problem "GitHub repository not notable enough (<20 forks, <20 watchers and <50 stars)" - end + urls = @specs.map(&:url) - return if Date.parse(metadata["created_at"]) <= (Date.today - 30) - problem "GitHub repository too new (<30 days old)" - end - - def audit_specs - if head_only?(formula) && formula.tap.to_s.downcase !~ %r{[-/]head-only$} - problem "Head-only (no stable download)" - end - - if devel_only?(formula) && formula.tap.to_s.downcase !~ %r{[-/]devel-only$} - problem "Devel-only (no stable download)" - end - - %w[Stable Devel HEAD].each do |name| - spec_name = name.downcase.to_sym - next unless spec = formula.send(spec_name) - - ra = ResourceAuditor.new(spec, spec_name, online: @online, strict: @strict).audit - problems.concat ra.problems.map { |problem| "#{name}: #{problem}" } - - spec.resources.each_value do |resource| - ra = ResourceAuditor.new(resource, spec_name, online: @online, strict: @strict).audit - problems.concat ra.problems.map { |problem| - "#{name} resource #{resource.name.inspect}: #{problem}" - } - end - - next if spec.patches.empty? - next unless @new_formula - problem "New formulae should not require patches to build. Patches should be submitted and accepted upstream first." - end - - %w[Stable Devel].each do |name| - next unless spec = formula.send(name.downcase) - version = spec.version - if version.to_s !~ /\d/ - problem "#{name}: version (#{version}) is set to a string without a digit" - end - if version.to_s.start_with?("HEAD") - problem "#{name}: non-HEAD version name (#{version}) should not begin with HEAD" - end - end - - if formula.stable && formula.devel - if formula.devel.version < formula.stable.version - problem "devel version #{formula.devel.version} is older than stable version #{formula.stable.version}" - elsif formula.devel.version == formula.stable.version - problem "stable and devel versions are identical" - end - end - - unstable_whitelist = %w[ - aalib 1.4rc5 - angolmois 2.0.0alpha2 - automysqlbackup 3.0-rc6 - aview 1.3.0rc1 - distcc 3.2rc1 - elm-format 0.6.0-alpha - ftgl 2.1.3-rc5 - hidapi 0.8.0-rc1 - libcaca 0.99b19 - nethack4 4.3.0-beta2 - opensyobon 1.0rc2 - premake 4.4-beta5 - pwnat 0.3-beta - pxz 4.999.9 - recode 3.7-beta2 - speexdsp 1.2rc3 - sqoop 1.4.6 - tcptraceroute 1.5beta7 - testssl 2.8rc3 - tiny-fugue 5.0b8 - vbindiff 3.0_beta4 - ].each_slice(2).to_a.map do |formula, version| - [formula, version.sub(/\d+$/, "")] - end - - gnome_devel_whitelist = %w[ - 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 - - stable = formula.stable - case stable&.url - when /[\d\._-](alpha|beta|rc\d)/ - matched = Regexp.last_match(1) - version_prefix = stable.version.to_s.sub(/\d+$/, "") - return if unstable_whitelist.include?([formula.name, version_prefix]) - problem "Stable version URLs should not contain #{matched}" - when %r{download\.gnome\.org/sources}, %r{ftp\.gnome\.org/pub/GNOME/sources}i - version_prefix = stable.version.to_s.split(".")[0..1].join(".") - return if gnome_devel_whitelist.include?([formula.name, version_prefix]) - version = Version.parse(stable.url) - if version >= Version.create("1.0") - minor_version = version.to_s.split(".", 3)[1].to_i - if minor_version.odd? - problem "#{stable.version} is a development release" + urls.each do |url| + if url =~ /darwin/i && (url =~ /x86_64/i || url =~ /amd64/i) + problem "#{url} looks like a binary package, not a source archive. Official taps are source-only." end end end - end - def audit_revision_and_version_scheme - return unless formula.tap # skip formula not from core or any taps - return unless formula.tap.git? # git log is required - return if @new_formula - - fv = FormulaVersions.new(formula) - - previous_version_and_checksum = fv.previous_version_and_checksum("origin/master") - [:stable, :devel].each do |spec_sym| - next unless spec = formula.send(spec_sym) - next unless previous_version_and_checksum[spec_sym][:version] == spec.version - next if previous_version_and_checksum[spec_sym][:checksum] == spec.checksum - problem "#{spec_sym}: sha256 changed without the version also changing; please create an issue upstream to rule out malicious circumstances and to find out why the file changed." + def quote_dep(dep) + dep.is_a?(Symbol) ? dep.inspect : "'#{dep}'" end - attributes = [:revision, :version_scheme] - attributes_map = fv.version_attributes_map(attributes, "origin/master") - - current_version_scheme = formula.version_scheme - [:stable, :devel].each do |spec| - spec_version_scheme_map = attributes_map[:version_scheme][spec] - next if spec_version_scheme_map.empty? - - version_schemes = spec_version_scheme_map.values.flatten - max_version_scheme = version_schemes.max - max_version = spec_version_scheme_map.select do |_, version_scheme| - version_scheme.first == max_version_scheme - end.keys.max - - if max_version_scheme && current_version_scheme < max_version_scheme - problem "version_scheme should not decrease (from #{max_version_scheme} to #{current_version_scheme})" - end - - if max_version_scheme && current_version_scheme >= max_version_scheme && - current_version_scheme > 1 && - !version_schemes.include?(current_version_scheme - 1) - problem "version_schemes should only increment by 1" - end - - formula_spec = formula.send(spec) - next unless formula_spec - - spec_version = formula_spec.version - next unless max_version - next if spec_version >= max_version - - above_max_version_scheme = current_version_scheme > max_version_scheme - map_includes_version = spec_version_scheme_map.keys.include?(spec_version) - next if !current_version_scheme.zero? && - (above_max_version_scheme || map_includes_version) - problem "#{spec} version should not decrease (from #{max_version} to #{spec_version})" + def problem_if_output(output) + problem(output) if output end - current_revision = formula.revision - revision_map = attributes_map[:revision][:stable] - if formula.stable && !revision_map.empty? - stable_revisions = revision_map[formula.stable.version] - stable_revisions ||= [] - max_revision = stable_revisions.max || 0 - - if current_revision < max_revision - problem "revision should not decrease (from #{max_revision} to #{current_revision})" + def audit + only_audits = @only + except_audits = @except + if only_audits && except_audits + odie "--only and --except cannot be used simultaneously!" end - stable_revisions -= [formula.revision] - if !current_revision.zero? && stable_revisions.empty? && - revision_map.keys.length > 1 - problem "'revision #{formula.revision}' should be removed" - elsif current_revision > 1 && - current_revision != max_revision && - !stable_revisions.include?(current_revision - 1) - problem "revisions should only increment by 1" + methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name| + name = audit_method_name.gsub(/^audit_/, "") + if only_audits + next unless only_audits.include?(name) + elsif except_audits + next if except_audits.include?(name) + end + send(audit_method_name) end - elsif !current_revision.zero? # head/devel-only formula - problem "'revision #{current_revision}' should be removed" + end + + private + + def problem(p) + @problems << p + end + + def head_only?(formula) + formula.head && formula.devel.nil? && formula.stable.nil? + end + + def devel_only?(formula) + formula.devel && formula.stable.nil? end end - def audit_text - bin_names = Set.new - bin_names << formula.name - bin_names += formula.aliases - [formula.bin, formula.sbin].each do |dir| - next unless dir.exist? - bin_names += dir.children.map(&:basename).map(&:to_s) + class ResourceAuditor + attr_reader :name, :version, :checksum, :url, :mirrors, :using, :specs, :owner + attr_reader :spec_name, :problems + + def initialize(resource, spec_name, options = {}) + @name = resource.name + @version = resource.version + @checksum = resource.checksum + @url = resource.url + @mirrors = resource.mirrors + @using = resource.using + @specs = resource.specs + @owner = resource.owner + @spec_name = spec_name + @online = options[:online] + @strict = options[:strict] + @problems = [] end - bin_names.each do |name| - ["system", "shell_output", "pipe_output"].each do |cmd| - if text =~ %r{(def test|test do).*(#{Regexp.escape(HOMEBREW_PREFIX)}/bin/)?#{cmd}[\(\s]+['"]#{Regexp.escape(name)}[\s'"]}m - problem %Q(fully scope test #{cmd} calls e.g. #{cmd} "\#{bin}/#{name}") + + def audit + audit_version + audit_download_strategy + audit_urls + self + end + + def audit_version + if version.nil? + problem "missing version" + elsif version.to_s.empty? + problem "version is set to an empty string" + elsif !version.detected_from_url? + version_text = version + version_url = Version.detect(url, specs) + if version_url.to_s == version_text.to_s && version.instance_of?(Version) + problem "version #{version_text} is redundant with version scanned from URL" + end + end + + if version.to_s.start_with?("v") + problem "version #{version} should not have a leading 'v'" + end + + return unless version.to_s =~ /_\d+$/ + problem "version #{version} should not end with an underline and a number" + end + + def audit_download_strategy + if url =~ %r{^(cvs|bzr|hg|fossil)://} || url =~ %r{^(svn)\+http://} + problem "Use of the #{$&} scheme is deprecated, pass `:using => :#{Regexp.last_match(1)}` instead" + end + + url_strategy = DownloadStrategyDetector.detect(url) + + if using == :git || url_strategy == GitDownloadStrategy + if specs[:tag] && !specs[:revision] + problem "Git should specify :revision when a :tag is specified." + end + end + + return unless using + + if using == :ssl3 || \ + (Object.const_defined?("CurlSSL3DownloadStrategy") && using == CurlSSL3DownloadStrategy) + problem "The SSL3 download strategy is deprecated, please choose a different URL" + elsif (Object.const_defined?("CurlUnsafeDownloadStrategy") && using == CurlUnsafeDownloadStrategy) || \ + (Object.const_defined?("UnsafeSubversionDownloadStrategy") && using == UnsafeSubversionDownloadStrategy) + problem "#{using.name} is deprecated, please choose a different URL" + end + + if using == :cvs + mod = specs[:module] + + problem "Redundant :module value in URL" if mod == name + + if url =~ %r{:[^/]+$} + mod = url.split(":").last + + if mod == name + problem "Redundant CVS module appended to URL" + else + problem "Specify CVS module as `:module => \"#{mod}\"` instead of appending it to the URL" + end + end + end + + return unless url_strategy == DownloadStrategyDetector.detect("", using) + problem "Redundant :using value in URL" + end + + def self.curl_openssl_and_deps + @curl_openssl_and_deps ||= begin + formulae_names = ["curl", "openssl"] + formulae_names += formulae_names.flat_map do |f| + Formula[f].recursive_dependencies.map(&:name) + end + formulae_names.uniq + rescue FormulaUnavailableError + [] + end + end + + def audit_urls + urls = [url] + mirrors + + curl_openssl_or_deps = ResourceAuditor.curl_openssl_and_deps.include?(owner.name) + + if spec_name == :stable && curl_openssl_or_deps + problem "should not use xz tarballs" if url.end_with?(".xz") + + unless urls.find { |u| u.start_with?("http://") } + problem "should always include at least one HTTP mirror" + end + end + + return unless @online + urls.each do |url| + next if !@strict && mirrors.include?(url) + + strategy = DownloadStrategyDetector.detect(url, using) + if strategy <= CurlDownloadStrategy && !url.start_with?("file") + # A `brew mirror`'ed URL is usually not yet reachable at the time of + # pull request. + next if url =~ %r{^https://dl.bintray.com/homebrew/mirror/} + if http_content_problem = curl_check_http_content(url, require_http: curl_openssl_or_deps) + problem http_content_problem + end + elsif strategy <= GitDownloadStrategy + 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 + problem "The URL #{url} is not a valid svn URL" + end end end end - end - def audit_lines - text.without_patch.split("\n").each_with_index do |line, lineno| - line_problems(line, lineno + 1) + def problem(text) + @problems << text end end - - def line_problems(line, _lineno) - # Check for string interpolation of single values. - if line =~ /(system|inreplace|gsub!|change_make_var!).*[ ,]"#\{([\w.]+)\}"/ - problem "Don't need to interpolate \"#{Regexp.last_match(2)}\" with #{Regexp.last_match(1)}" - end - - # Check for string concatenation; prefer interpolation - if line =~ /(#\{\w+\s*\+\s*['"][^}]+\})/ - problem "Try not to concatenate paths in string interpolation:\n #{Regexp.last_match(1)}" - end - - # Prefer formula path shortcuts in Pathname+ - if line =~ %r{\(\s*(prefix\s*\+\s*(['"])(bin|include|libexec|lib|sbin|share|Frameworks)[/'"])} - problem "\"(#{Regexp.last_match(1)}...#{Regexp.last_match(2)})\" should be \"(#{Regexp.last_match(3).downcase}+...)\"" - end - - problem "Use separate make calls" if line.include?("make && make") - - if line =~ /JAVA_HOME/i && !formula.requirements.map(&:class).include?(JavaRequirement) - problem "Use `depends_on :java` to set JAVA_HOME" - end - - return unless @strict - - if @official_tap && line.include?("env :std") - problem "`env :std` in official tap formulae is deprecated" - end - - if line.include?("env :userpaths") - problem "`env :userpaths` in formulae is deprecated" - end - - if line =~ /system ((["'])[^"' ]*(?:\s[^"' ]*)+\2)/ - bad_system = Regexp.last_match(1) - unless %w[| < > & ; *].any? { |c| bad_system.include? c } - good_system = bad_system.gsub(" ", "\", \"") - problem "Use `system #{good_system}` instead of `system #{bad_system}` " - end - end - - problem "`#{Regexp.last_match(1)}` is now unnecessary" if line =~ /(require ["']formula["'])/ - - if line =~ %r{#\{share\}/#{Regexp.escape(formula.name)}[/'"]} - problem "Use \#{pkgshare} instead of \#{share}/#{formula.name}" - end - - return unless line =~ %r{share(\s*[/+]\s*)(['"])#{Regexp.escape(formula.name)}(?:\2|/)} - problem "Use pkgshare instead of (share#{Regexp.last_match(1)}\"#{formula.name}\")" - end - - def audit_reverse_migration - # Only enforce for new formula being re-added to core and official taps - return unless @strict - return unless @official_tap - return unless formula.tap.tap_migrations.key?(formula.name) - - problem <<~EOS - #{formula.name} seems to be listed in tap_migrations.json! - Please remove #{formula.name} from present tap & tap_migrations.json - before submitting it to Homebrew/homebrew-#{formula.tap.repo}. - EOS - end - - def audit_prefix_has_contents - return unless formula.prefix.directory? - return unless Keg.new(formula.prefix).empty_installation? - - problem <<~EOS - The installation seems to be empty. Please ensure the prefix - is set correctly and expected files are installed. - The prefix configure/make argument may be case-sensitive. - EOS - end - - def audit_url_is_not_binary - return unless @official_tap - - urls = @specs.map(&:url) - - urls.each do |url| - if url =~ /darwin/i && (url =~ /x86_64/i || url =~ /amd64/i) - problem "#{url} looks like a binary package, not a source archive. Official taps are source-only." - end - end - end - - def quote_dep(dep) - dep.is_a?(Symbol) ? dep.inspect : "'#{dep}'" - end - - def problem_if_output(output) - problem(output) if output - end - - def audit - 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 - next unless only_audits.include?(name) - elsif except_audits - next if except_audits.include?(name) - end - send(audit_method_name) - end - end - - private - - def problem(p) - @problems << p - end - - def head_only?(formula) - formula.head && formula.devel.nil? && formula.stable.nil? - end - - def devel_only?(formula) - formula.devel && formula.stable.nil? - end -end - -class ResourceAuditor - attr_reader :name, :version, :checksum, :url, :mirrors, :using, :specs, :owner - attr_reader :spec_name, :problems - - def initialize(resource, spec_name, options = {}) - @name = resource.name - @version = resource.version - @checksum = resource.checksum - @url = resource.url - @mirrors = resource.mirrors - @using = resource.using - @specs = resource.specs - @owner = resource.owner - @spec_name = spec_name - @online = options[:online] - @strict = options[:strict] - @problems = [] - end - - def audit - audit_version - audit_download_strategy - audit_urls - self - end - - def audit_version - if version.nil? - problem "missing version" - elsif version.to_s.empty? - problem "version is set to an empty string" - elsif !version.detected_from_url? - version_text = version - version_url = Version.detect(url, specs) - if version_url.to_s == version_text.to_s && version.instance_of?(Version) - problem "version #{version_text} is redundant with version scanned from URL" - end - end - - if version.to_s.start_with?("v") - problem "version #{version} should not have a leading 'v'" - end - - return unless version.to_s =~ /_\d+$/ - problem "version #{version} should not end with an underline and a number" - end - - def audit_download_strategy - if url =~ %r{^(cvs|bzr|hg|fossil)://} || url =~ %r{^(svn)\+http://} - problem "Use of the #{$&} scheme is deprecated, pass `:using => :#{Regexp.last_match(1)}` instead" - end - - url_strategy = DownloadStrategyDetector.detect(url) - - if using == :git || url_strategy == GitDownloadStrategy - if specs[:tag] && !specs[:revision] - problem "Git should specify :revision when a :tag is specified." - end - end - - return unless using - - if using == :ssl3 || \ - (Object.const_defined?("CurlSSL3DownloadStrategy") && using == CurlSSL3DownloadStrategy) - problem "The SSL3 download strategy is deprecated, please choose a different URL" - elsif (Object.const_defined?("CurlUnsafeDownloadStrategy") && using == CurlUnsafeDownloadStrategy) || \ - (Object.const_defined?("UnsafeSubversionDownloadStrategy") && using == UnsafeSubversionDownloadStrategy) - problem "#{using.name} is deprecated, please choose a different URL" - end - - if using == :cvs - mod = specs[:module] - - problem "Redundant :module value in URL" if mod == name - - if url =~ %r{:[^/]+$} - mod = url.split(":").last - - if mod == name - problem "Redundant CVS module appended to URL" - else - problem "Specify CVS module as `:module => \"#{mod}\"` instead of appending it to the URL" - end - end - end - - return unless url_strategy == DownloadStrategyDetector.detect("", using) - problem "Redundant :using value in URL" - end - - def self.curl_openssl_and_deps - @curl_openssl_and_deps ||= begin - formulae_names = ["curl", "openssl"] - formulae_names += formulae_names.flat_map do |f| - Formula[f].recursive_dependencies.map(&:name) - end - formulae_names.uniq - rescue FormulaUnavailableError - [] - end - end - - def audit_urls - urls = [url] + mirrors - - curl_openssl_or_deps = ResourceAuditor.curl_openssl_and_deps.include?(owner.name) - - if spec_name == :stable && curl_openssl_or_deps - problem "should not use xz tarballs" if url.end_with?(".xz") - - unless urls.find { |u| u.start_with?("http://") } - problem "should always include at least one HTTP mirror" - end - end - - return unless @online - urls.each do |url| - next if !@strict && mirrors.include?(url) - - strategy = DownloadStrategyDetector.detect(url, using) - if strategy <= CurlDownloadStrategy && !url.start_with?("file") - # A `brew mirror`'ed URL is usually not yet reachable at the time of - # pull request. - next if url =~ %r{^https://dl.bintray.com/homebrew/mirror/} - if http_content_problem = curl_check_http_content(url, require_http: curl_openssl_or_deps) - problem http_content_problem - end - elsif strategy <= GitDownloadStrategy - 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 - problem "The URL #{url} is not a valid svn URL" - end - end - end - end - - def problem(text) - @problems << text - end end diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index b05277d054..ab222b8832 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -1,4 +1,4 @@ -#: * `bottle` [`--verbose`] [`--no-rebuild`|`--keep-old`] [`--skip-relocation`] [`--root-url=`] [`--force-core-tap`] : +#: * `bottle` [`--verbose`] [`--no-rebuild`|`--keep-old`] [`--skip-relocation`] [`--or-later`] [`--root-url=`] [`--force-core-tap`] : #: Generate a bottle (binary package) from a formula installed with #: `--build-bottle`. #: @@ -15,6 +15,8 @@ #: If `--root-url` is passed, use the specified as the root of the #: bottle's URL instead of Homebrew's default. #: +#: If `--or-later` is passed, append _or_later to the bottle tag. +#: #: If `--force-core-tap` is passed, build a bottle even if is not #: in homebrew/core or any installed taps. #: @@ -37,7 +39,6 @@ require "formula_versions" require "cli_parser" require "utils/inreplace" require "erb" -require "extend/pathname" BOTTLE_ERB = <<-EOS.freeze bottle do @@ -58,7 +59,7 @@ BOTTLE_ERB = <<-EOS.freeze <% checksums.each do |checksum_type, checksum_values| %> <% checksum_values.each do |checksum_value| %> <% checksum, macos = checksum_value.shift %> - <%= checksum_type %> "<%= checksum %>" => :<%= macos %> + <%= checksum_type %> "<%= checksum %>" => :<%= macos %><%= "_or_later" if Homebrew.args.or_later? %> <% end %> <% end %> end @@ -79,7 +80,9 @@ module Homebrew switch "--write" switch "--no-commit" switch "--json" + switch "--or-later" switch :verbose + switch :debug flag "--root-url" end @@ -114,7 +117,7 @@ module Homebrew linked_libraries = Keg.file_linked_libraries(file, string) result ||= !linked_libraries.empty? - if @args.verbose? + if Homebrew.args.verbose? print_filename.call(string, file) unless linked_libraries.empty? linked_libraries.each do |lib| puts " #{Tty.bold}-->#{Tty.reset} links to #{lib}" @@ -137,7 +140,7 @@ module Homebrew end end - next unless @args.verbose? && !text_matches.empty? + next unless Homebrew.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}" @@ -158,7 +161,7 @@ module Homebrew absolute_symlinks_start_with_string << pn if link.to_s.start_with?(string) end - if @args.verbose? + if Homebrew.args.verbose? unless absolute_symlinks_start_with_string.empty? opoo "Absolute symlink starting with #{string}:" absolute_symlinks_start_with_string.each do |pn| @@ -299,7 +302,7 @@ module Homebrew end skip_relocation = relocatable && !keg.require_relocation? end - puts if !relocatable && @args.verbose? + puts if !relocatable && Homebrew.args.verbose? rescue Interrupt ignore_interrupts { bottle_path.unlink if bottle_path.exist? } raise @@ -360,6 +363,8 @@ module Homebrew puts output return unless @args.json? + tag = Utils::Bottles.tag.to_s + tag += "_or_later" if @args.or_later? json = { f.full_name => { "formula" => { @@ -372,7 +377,7 @@ module Homebrew "cellar" => bottle.cellar.to_s, "rebuild" => bottle.rebuild, "tags" => { - Utils::Bottles.tag.to_s => { + tag => { "filename" => filename.to_s, "sha256" => sha256, }, diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 1f44fa549e..b5c1dccdd7 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -131,6 +131,9 @@ module Homebrew ENV[env] = homebrew_env end + gh_api_errors = [GitHub::AuthenticationFailedError, GitHub::HTTPNotFoundError, + GitHub::RateLimitExceededError, GitHub::Error, JSON::ParserError].freeze + formula = ARGV.formulae.first if formula @@ -314,73 +317,41 @@ module Homebrew end end - unless Formula["hub"].any_version_installed? - if ARGV.dry_run? - ohai "brew install hub" - else - safe_system "brew", "install", "hub" - end - end - formula.path.parent.cd do branch = "#{formula.name}-#{new_formula_version}" git_dir = Utils.popen_read("git rev-parse --git-dir").chomp shallow = !git_dir.empty? && File.exist?("#{git_dir}/shallow") - hub_args = [] - git_final_checkout_args = [] - if ARGV.include?("--no-browse") - git_final_checkout_args << "--quiet" - else - hub_args << "--browse" - end - if ARGV.dry_run? - ohai "hub fork # read $HUB_REMOTE" + ohai "fork repository with GitHub API" ohai "git fetch --unshallow origin" if shallow ohai "git checkout --no-track -b #{branch} origin/master" ohai "git commit --no-edit --verbose --message='#{formula.name} #{new_formula_version}#{devel_message}' -- #{formula.path}" ohai "git push --set-upstream $HUB_REMOTE #{branch}:#{branch}" - ohai "hub pull-request #{hub_args.join(" ")} -m '#{formula.name} #{new_formula_version}#{devel_message}'" + ohai "create pull request with GitHub API" ohai "git checkout -" else - reply = IO.popen(["hub", "fork"], "r+", err: "/dev/null") do |io| - reader = Thread.new { io.read } - sleep 1 - io.close_write - reader.value - end - if reply.to_s.include? "username:" + begin + response = GitHub.create_fork(formula.tap.full_name) + # GitHub API responds immediately but fork takes a few seconds to be ready. + sleep 3 + rescue *gh_api_errors => e formula.path.atomic_write(backup_file) unless ARGV.dry_run? - git_path = "$(brew --repo #{formula.tap})" if formula.tap - git_path ||= formula.path.parent - odie <<~EOS - Retry after configuring hub by running: - hub -C "#{git_path}" fork - Or setting HOMEBREW_GITHUB_TOKEN with at least 'public_repo' scope. - EOS + odie "Unable to fork: #{e.message}!" end - remote = reply[/remote:? (\S+)/, 1] - - # repeat for hub 2.2 backwards compatibility: - remote = Utils.popen_read("hub", "fork", err: :out)[/remote:? (\S+)/, 1] if remote.to_s.empty? - - if remote.to_s.empty? - formula.path.atomic_write(backup_file) unless ARGV.dry_run? - odie "cannot get remote from 'hub'!" - end + remote_url = response.fetch("clone_url") + username = response.fetch("owner").fetch("login") safe_system "git", "fetch", "--unshallow", "origin" if shallow safe_system "git", "checkout", "--no-track", "-b", branch, "origin/master" safe_system "git", "commit", "--no-edit", "--verbose", "--message=#{formula.name} #{new_formula_version}#{devel_message}", "--", formula.path - safe_system "git", "push", "--set-upstream", remote, "#{branch}:#{branch}" + safe_system "git", "push", "--set-upstream", remote_url, "#{branch}:#{branch}" + safe_system "git", "checkout", "--quiet", "-" pr_message = <<~EOS - #{formula.name} #{new_formula_version}#{devel_message} - Created with `brew bump-formula-pr`. EOS user_message = ARGV.value("message") @@ -391,8 +362,19 @@ module Homebrew #{user_message} EOS end - safe_system "hub", "pull-request", *hub_args, "-m", pr_message - safe_system "git", "checkout", *git_final_checkout_args, "-" + pr_title = "#{formula.name} #{new_formula_version}#{devel_message}" + + begin + url = GitHub.create_pull_request(formula.tap.full_name, pr_title, + "#{username}:#{branch}", "master", pr_message)["html_url"] + if ARGV.include?("--no-browse") + puts url + else + exec_browser url + end + rescue *gh_api_errors => e + odie "Unable to open pull request: #{e.message}!" + end end end end diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb index 514d3b6c30..d9905a39da 100644 --- a/Library/Homebrew/dev-cmd/create.rb +++ b/Library/Homebrew/dev-cmd/create.rb @@ -65,7 +65,7 @@ module Homebrew # Don't allow blacklisted formula, or names that shadow aliases, # unless --force is specified. unless ARGV.force? - if reason = Homebrew::MissingFormula.blacklisted_reason(fc.name) + if reason = MissingFormula.blacklisted_reason(fc.name) raise "#{fc.name} is blacklisted for creation.\n#{reason}\nIf you really want to create this formula use --force." end @@ -185,8 +185,9 @@ class FormulaCreator <% if mode == :cmake %> depends_on "cmake" => :build <% elsif mode == :meson %> - depends_on "meson" => :build + depends_on "meson-internal" => :build depends_on "ninja" => :build + depends_on "python" => :build <% elsif mode.nil? %> # depends_on "cmake" => :build <% end %> @@ -202,10 +203,11 @@ class FormulaCreator "--disable-silent-rules", "--prefix=\#{prefix}" <% elsif mode == :meson %> + ENV.refurbish_args + mkdir "build" do system "meson", "--prefix=\#{prefix}", ".." system "ninja" - system "ninja", "test" system "ninja", "install" end <% else %> diff --git a/Library/Homebrew/dev-cmd/edit.rb b/Library/Homebrew/dev-cmd/edit.rb index 0861a4bb1e..bcbf5b7d5d 100644 --- a/Library/Homebrew/dev-cmd/edit.rb +++ b/Library/Homebrew/dev-cmd/edit.rb @@ -11,8 +11,10 @@ module Homebrew module_function def edit - args = Homebrew::CLI::Parser.parse do - switch "--force" + Homebrew::CLI::Parser.parse do + switch :force + switch :verbose + switch :debug end unless (HOMEBREW_REPOSITORY/".git").directory? @@ -41,7 +43,7 @@ module Homebrew paths = ARGV.named.map do |name| path = Formulary.path(name) - raise FormulaUnavailableError, name unless path.file? || args.force? + raise FormulaUnavailableError, name unless path.file? || Homebrew.args.force? path end diff --git a/Library/Homebrew/dev-cmd/formula.rb b/Library/Homebrew/dev-cmd/formula.rb index 67d11edce2..eb6cd087ea 100644 --- a/Library/Homebrew/dev-cmd/formula.rb +++ b/Library/Homebrew/dev-cmd/formula.rb @@ -2,11 +2,17 @@ #: Display the path where is located. require "formula" +require "cli_parser" module Homebrew module_function def formula + Homebrew::CLI::Parser.parse do + switch :debug + switch :verbose + end + raise FormulaUnspecifiedError if ARGV.named.empty? ARGV.resolved_formulae.each { |f| puts f.path } end diff --git a/Library/Homebrew/dev-cmd/linkage.rb b/Library/Homebrew/dev-cmd/linkage.rb index c33c181a1e..834ed066ed 100644 --- a/Library/Homebrew/dev-cmd/linkage.rb +++ b/Library/Homebrew/dev-cmd/linkage.rb @@ -21,7 +21,7 @@ module Homebrew result = LinkageChecker.new(keg) if ARGV.include?("--test") result.display_test_output - Homebrew.failed = true if result.broken_dylibs? + Homebrew.failed = true if result.broken_library_linkage? elsif ARGV.include?("--reverse") result.display_reverse_output else diff --git a/Library/Homebrew/dev-cmd/mirror.rb b/Library/Homebrew/dev-cmd/mirror.rb index bf19ee3c57..7e3f2821f9 100644 --- a/Library/Homebrew/dev-cmd/mirror.rb +++ b/Library/Homebrew/dev-cmd/mirror.rb @@ -1,11 +1,18 @@ #: @hide_from_man_page -#: * `mirror` [`--test`] : +#: * `mirror` : #: Reuploads the stable URL for a formula to Bintray to use it as a mirror. +require "cli_parser" + module Homebrew module_function def mirror + Homebrew::CLI::Parser.parse do + switch :debug + switch :verbose + end + odie "This command requires at least formula argument!" if ARGV.named.empty? bintray_user = ENV["HOMEBREW_BINTRAY_USER"] diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb index c8006d7781..3947846963 100644 --- a/Library/Homebrew/dev-cmd/pull.rb +++ b/Library/Homebrew/dev-cmd/pull.rb @@ -50,12 +50,10 @@ require "net/http" require "net/https" -require "utils" require "json" require "cli_parser" require "formula" require "formulary" -require "tap" require "version" require "pkg_version" @@ -86,8 +84,10 @@ module Homebrew switch "--no-pbcopy" switch "--no-publish" switch "--warn-on-publish-failure" - flag "--bintray-org", required: true - flag "--test-bot-user", required: true + switch :verbose + switch :debug + flag "--bintray-org=" + flag "--test-bot-user=" end if ARGV.named.empty? diff --git a/Library/Homebrew/dev-cmd/release-notes.rb b/Library/Homebrew/dev-cmd/release-notes.rb index 892a4a83e1..a930aad23f 100644 --- a/Library/Homebrew/dev-cmd/release-notes.rb +++ b/Library/Homebrew/dev-cmd/release-notes.rb @@ -1,6 +1,6 @@ #: * `release-notes` [`--markdown`] [] []: #: Output the merged pull requests on Homebrew/brew between two Git refs. -#: If no is provided it defaults to the newest tag. +#: If no is provided it defaults to the latest tag. #: If no is provided it defaults to `origin/master`. #: #: If `--markdown` is passed, output as a Markdown list. @@ -16,19 +16,21 @@ module Homebrew end previous_tag = ARGV.named.first - previous_tag ||= Utils.popen_read("git tag --list --sort=-version:refname") - .lines.first.chomp + previous_tag ||= Utils.popen_read( + "git", "-C", HOMEBREW_REPOSITORY, "tag", "--list", "--sort=-version:refname" + ).lines.first.chomp odie "Could not find any previous tags!" unless previous_tag end_ref = ARGV.named[1] || "origin/master" [previous_tag, end_ref].each do |ref| - next if quiet_system "git", "rev-parse", "--verify", "--quiet", ref + next if quiet_system "git", "-C", HOMEBREW_REPOSITORY, "rev-parse", "--verify", "--quiet", ref odie "Ref #{ref} does not exist!" end - output = Utils.popen_read("git log --pretty=format:'%s >> - %b%n' '#{previous_tag}'..'#{end_ref}'") - .lines.grep(/Merge pull request/) + output = Utils.popen_read( + "git", "-C", HOMEBREW_REPOSITORY, "log", "--pretty=format:'%s >> - %b%n'", "#{previous_tag}..#{end_ref}" + ).lines.grep(/Merge pull request/) output.map! do |s| s.gsub(%r{.*Merge pull request #(\d+) from ([^/]+)/[^>]*(>>)*}, diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb index 31299d2b0b..e29b143c39 100644 --- a/Library/Homebrew/dev-cmd/tap-new.rb +++ b/Library/Homebrew/dev-cmd/tap-new.rb @@ -2,6 +2,7 @@ #: Generate the template files for a new tap. require "tap" +require "cli_parser" module Homebrew module_function @@ -14,6 +15,11 @@ module Homebrew end def tap_new + Homebrew::CLI::Parser.parse do + switch :debug + switch :verbose + end + raise "A tap argument is required" if ARGV.named.empty? tap = Tap.fetch(ARGV.named.first) diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index 57c00dafc7..3edc12ed5b 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -17,7 +17,6 @@ require "cli_parser" require "fileutils" -require "tap" module Homebrew module_function @@ -26,11 +25,12 @@ module Homebrew 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 + switch :debug + switch :verbose + flag "--only=" + flag "--seed=" end HOMEBREW_LIBRARY_PATH.cd do @@ -113,6 +113,7 @@ module Homebrew end unless OS.linux? + args << "--tag" << "~needs_linux" files = files.reject { |p| p =~ %r{^test/os/linux(/.*|_spec\.rb)$} } end diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb index c0e3f64a00..d72e12b249 100644 --- a/Library/Homebrew/dev-cmd/update-test.rb +++ b/Library/Homebrew/dev-cmd/update-test.rb @@ -23,8 +23,10 @@ module Homebrew args = Homebrew::CLI::Parser.parse do switch "--to-tag" switch "--keep-tmp" - flag "--commit", required: true - flag "--before", required: true + switch :verbose + switch :debug + flag "--commit=" + flag "--before=" end ENV["HOMEBREW_UPDATE_TEST"] = "1" diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 36df53794f..736f35ff19 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -107,18 +107,6 @@ module Homebrew EOS end - # See https://github.com/Homebrew/legacy-homebrew/pull/9986 - def check_path_for_trailing_slashes - bad_paths = PATH.new(ENV["HOMEBREW_PATH"]).select { |p| p.end_with?("/") } - return if bad_paths.empty? - - inject_file_list bad_paths, <<~EOS - Some directories in your path end in a slash. - Directories in your path should not end in a slash. This can break other - doctor checks. The following directories should be edited: - EOS - end - # Anaconda installs multiple system & brew dupes, including OpenSSL, Python, # sqlite, libpng, Qt, etc. Regularly breaks compile on Vim, MacVim and others. # Is flagged as part of the *-config script checks below, but people seem @@ -492,21 +480,6 @@ module Homebrew EOS end - def check_user_curlrc - curlrc_found = %w[CURL_HOME HOME].any? do |var| - ENV[var] && File.exist?("#{ENV[var]}/.curlrc") - end - return unless curlrc_found - - <<~EOS - You have a curlrc file - If you have trouble downloading packages with Homebrew, then maybe this - is the problem? If the following command doesn't work, then try removing - your curlrc: - curl #{Formatter.url("https://github.com")} - EOS - end - def check_for_gettext find_relative_paths("lib/libgettextlib.dylib", "lib/libintl.dylib", @@ -620,18 +593,6 @@ module Homebrew message end - def check_ssl_cert_file - return unless ENV.key?("SSL_CERT_FILE") - <<~EOS - Setting SSL_CERT_FILE can break downloading files; if that happens - you should unset it before running Homebrew. - - Homebrew uses the system curl which uses system certificates by - default. Setting SSL_CERT_FILE makes it use an outdated OpenSSL, which - does not support modern OpenSSL certificate stores. - EOS - end - def check_for_symlinked_cellar return unless HOMEBREW_CELLAR.exist? return unless HOMEBREW_CELLAR.symlink? @@ -811,28 +772,6 @@ module Homebrew false end - def check_for_linked_keg_only_brews - return unless HOMEBREW_CELLAR.exist? - - linked = Formula.installed.sort.select do |f| - f.keg_only? && __check_linked_brew(f) - end - return if linked.empty? - - inject_file_list linked.map(&:full_name), <<~EOS - Some keg-only formulae are linked into the Cellar. - Linking a keg-only formula, such as gettext, into the cellar with - `brew link ` will cause other formulae to detect them during - the `./configure` step. This may cause problems when compiling those - other formulae. - - Binaries provided by keg-only formulae may override system binaries - with other strange results. - - You may wish to `brew unlink` these brews: - EOS - end - def check_for_other_frameworks # Other frameworks that are known to cause problems when present frameworks_to_check = %w[ @@ -893,53 +832,6 @@ module Homebrew EOS end - def check_for_enthought_python - return unless which "enpkg" - - <<~EOS - Enthought Python was found in your PATH. - This can cause build problems, as this software installs its own - copies of iconv and libxml2 into directories that are picked up by - other build systems. - EOS - end - - def check_for_library_python - return unless File.exist?("/Library/Frameworks/Python.framework") - - <<~EOS - Python is installed at /Library/Frameworks/Python.framework - - Homebrew only supports building against the System-provided Python or a - brewed Python. In particular, Pythons installed to /Library can interfere - with other software installs. - EOS - end - - def check_for_old_homebrew_share_python_in_path - message = "" - ["", "3"].map do |suffix| - next unless paths.include?((HOMEBREW_PREFIX/"share/python#{suffix}").to_s) - message += <<~EOS - #{HOMEBREW_PREFIX}/share/python#{suffix} is not needed in PATH. - EOS - end - unless message.empty? - message += <<~EOS - - Formerly homebrew put Python scripts you installed via `pip` or `pip3` - (or `easy_install`) into that directory above but now it can be removed - from your PATH variable. - Python scripts will now install into #{HOMEBREW_PREFIX}/bin. - You can delete anything, except 'Extras', from the #{HOMEBREW_PREFIX}/share/python - (and #{HOMEBREW_PREFIX}/share/python@2) dir and install affected Python packages - anew with `pip install --upgrade`. - EOS - end - - message unless message.empty? - end - def check_for_bad_python_symlink return unless which "python" `python -V 2>&1` =~ /Python (\d+)\./ diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index b50ae317c7..1ed474cfb1 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -22,6 +22,7 @@ class AbstractDownloadStrategy @url = resource.url @version = resource.version @meta = resource.specs + @shutup = false extend Pourable if meta[:bottle] end @@ -80,7 +81,7 @@ class AbstractDownloadStrategy def safe_system(*args) if @shutup - quiet_system(*args) || raise(ErrorDuringExecution.new(args.shift, *args)) + quiet_system(*args) || raise(ErrorDuringExecution.new(args.shift, args)) else super(*args) end @@ -594,6 +595,70 @@ class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDo end end +# ScpDownloadStrategy downloads files using ssh via scp. To use it, add +# ":using => ScpDownloadStrategy" to the URL section of your formula or +# provide a URL starting with scp://. This strategy uses ssh credentials for +# authentication. If a public/private keypair is configured, it will not +# prompt for a password. +# +# Usage: +# +# class Abc < Formula +# url "scp://example.com/src/abc.1.0.tar.gz" +# ... +class ScpDownloadStrategy < AbstractFileDownloadStrategy + attr_reader :tarball_path, :temporary_path + + def initialize(name, resource) + super + @tarball_path = HOMEBREW_CACHE/"#{name}-#{version}#{ext}" + @temporary_path = Pathname.new("#{cached_location}.incomplete") + parse_url_pattern + end + + def parse_url_pattern + url_pattern = %r{scp://([^@]+@)?([^@:/]+)(:\d+)?/(\S+)} + if @url !~ url_pattern + raise ScpDownloadStrategyError, "Invalid URL for scp: #{@url}" + end + + _, @user, @host, @port, @path = *@url.match(url_pattern) + end + + def fetch + ohai "Downloading #{@url}" + + if cached_location.exist? + puts "Already downloaded: #{cached_location}" + else + begin + safe_system "scp", scp_source, temporary_path.to_s + rescue ErrorDuringExecution + raise ScpDownloadStrategyError, "Failed to run scp #{scp_source}" + end + + ignore_interrupts { temporary_path.rename(cached_location) } + end + end + + def cached_location + tarball_path + end + + def clear_cache + super + rm_rf(temporary_path) + end + + private + + def scp_source + path_prefix = "/" unless @path.start_with?("~") + port_arg = "-P #{@port[1..-1]} " if @port + "#{port_arg}#{@user}#{@host}:#{path_prefix}#{@path}" + end +end + class SubversionDownloadStrategy < VCSDownloadStrategy def initialize(name, resource) super @@ -1140,6 +1205,8 @@ class DownloadStrategyDetector when %r{^s3://} require_aws_sdk S3DownloadStrategy + when %r{^scp://} + ScpDownloadStrategy else CurlDownloadStrategy end diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index b3acf821ec..a33ed47abf 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -515,6 +515,13 @@ class CurlDownloadStrategyError < RuntimeError end end +# raised in ScpDownloadStrategy.fetch +class ScpDownloadStrategyError < RuntimeError + def initialize(cause) + super "Download failed: #{cause}" + end +end + # raised by safe_system in utils.rb class ErrorDuringExecution < RuntimeError def initialize(cmd, args = []) diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb index 5a6b779d0e..9ba3a244a4 100644 --- a/Library/Homebrew/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/ENV/shared.rb @@ -1,7 +1,5 @@ -require "formula" require "compilers" require "development_tools" -require "PATH" # Homebrew extends Ruby's `ENV` to make our code more readable. # Implemented in {SharedEnvExtension} and either {Superenv} or diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index 3d082dc837..17e0fd67a0 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -13,6 +13,8 @@ module Stdenv def setup_build_environment(formula = nil) super + self["HOMEBREW_ENV"] = "std" + PATH.new(ENV["HOMEBREW_PATH"]).each { |p| prepend_path "PATH", p } # Set the default pkg-config search path, overriding the built-in paths diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb index 660b9b3a3c..c9fac5b5cd 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -38,6 +38,7 @@ module Superenv super send(compiler) + self["HOMEBREW_ENV"] = "super" self["MAKEFLAGS"] ||= "-j#{determine_make_jobs}" self["PATH"] = determine_path self["PKG_CONFIG_PATH"] = determine_pkg_config_path diff --git a/Library/Homebrew/extend/fileutils.rb b/Library/Homebrew/extend/fileutils.rb index 6286e48c01..ea2d51c01b 100644 --- a/Library/Homebrew/extend/fileutils.rb +++ b/Library/Homebrew/extend/fileutils.rb @@ -1,5 +1,4 @@ require "fileutils" -require "tmpdir" require "etc" # Homebrew extends Ruby's `FileUtils` to make our code more readable. diff --git a/Library/Homebrew/extend/module.rb b/Library/Homebrew/extend/module.rb index f4ea4de55a..b314543739 100644 --- a/Library/Homebrew/extend/module.rb +++ b/Library/Homebrew/extend/module.rb @@ -6,7 +6,9 @@ class Module attrs.each do |attr| module_eval <<-EOS, file, line def #{attr}(val=nil) - val.nil? ? @#{attr} : @#{attr} = val + @#{attr} ||= nil + return @#{attr} if val.nil? + @#{attr} = val end EOS end diff --git a/Library/Homebrew/extend/optparse.rb b/Library/Homebrew/extend/optparse.rb index 784d6d699d..801f7baddd 100644 --- a/Library/Homebrew/extend/optparse.rb +++ b/Library/Homebrew/extend/optparse.rb @@ -1,5 +1,4 @@ require "optparse" -require "pathname" OptionParser.accept Pathname do |path| Pathname(path).expand_path if path diff --git a/Library/Homebrew/extend/os/bottles.rb b/Library/Homebrew/extend/os/bottles.rb index 146b807a4a..6ee9a2146e 100644 --- a/Library/Homebrew/extend/os/bottles.rb +++ b/Library/Homebrew/extend/os/bottles.rb @@ -1,2 +1 @@ -require "utils/bottles" require "extend/os/mac/utils/bottles" if OS.mac? diff --git a/Library/Homebrew/extend/os/dependency_collector.rb b/Library/Homebrew/extend/os/dependency_collector.rb index 56fcad31d0..10131c916d 100644 --- a/Library/Homebrew/extend/os/dependency_collector.rb +++ b/Library/Homebrew/extend/os/dependency_collector.rb @@ -1,2 +1 @@ -require "dependency_collector" require "extend/os/mac/dependency_collector" if OS.mac? diff --git a/Library/Homebrew/extend/os/development_tools.rb b/Library/Homebrew/extend/os/development_tools.rb index 5bd5cb81a0..2d748074d1 100644 --- a/Library/Homebrew/extend/os/development_tools.rb +++ b/Library/Homebrew/extend/os/development_tools.rb @@ -1,2 +1 @@ -require "development_tools" require "extend/os/mac/development_tools" if OS.mac? diff --git a/Library/Homebrew/extend/os/diagnostic.rb b/Library/Homebrew/extend/os/diagnostic.rb index f8f53b1f4f..3e0d104fc4 100644 --- a/Library/Homebrew/extend/os/diagnostic.rb +++ b/Library/Homebrew/extend/os/diagnostic.rb @@ -1,2 +1 @@ -require "diagnostic" require "extend/os/mac/diagnostic" if OS.mac? diff --git a/Library/Homebrew/extend/os/emoji.rb b/Library/Homebrew/extend/os/emoji.rb index 8fd99e1d3e..59efced1d7 100644 --- a/Library/Homebrew/extend/os/emoji.rb +++ b/Library/Homebrew/extend/os/emoji.rb @@ -1,3 +1 @@ -require "os" -require "emoji" require "extend/os/mac/emoji" if OS.mac? diff --git a/Library/Homebrew/extend/os/extend/ENV/shared.rb b/Library/Homebrew/extend/os/extend/ENV/shared.rb index e9574eb583..405c442912 100644 --- a/Library/Homebrew/extend/os/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/os/extend/ENV/shared.rb @@ -1,2 +1 @@ -require "extend/ENV/shared" require "extend/os/mac/extend/ENV/shared" if OS.mac? diff --git a/Library/Homebrew/extend/os/extend/ENV/std.rb b/Library/Homebrew/extend/os/extend/ENV/std.rb index 18ede5b9ed..7d117c626e 100644 --- a/Library/Homebrew/extend/os/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/extend/ENV/std.rb @@ -1,4 +1,3 @@ -require "extend/ENV/std" if OS.mac? require "extend/os/mac/extend/ENV/std" elsif OS.linux? diff --git a/Library/Homebrew/extend/os/extend/ENV/super.rb b/Library/Homebrew/extend/os/extend/ENV/super.rb index 27c49eb849..a04f559f23 100644 --- a/Library/Homebrew/extend/os/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/extend/ENV/super.rb @@ -1,2 +1 @@ -require "extend/ENV/super" require "extend/os/mac/extend/ENV/super" if OS.mac? diff --git a/Library/Homebrew/extend/os/formula_cellar_checks.rb b/Library/Homebrew/extend/os/formula_cellar_checks.rb index 66b5b80d3d..7198179563 100644 --- a/Library/Homebrew/extend/os/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/formula_cellar_checks.rb @@ -1,2 +1 @@ -require "formula_cellar_checks" require "extend/os/mac/formula_cellar_checks" if OS.mac? diff --git a/Library/Homebrew/extend/os/keg_relocate.rb b/Library/Homebrew/extend/os/keg_relocate.rb index 25a74286a4..7c805a7ae1 100644 --- a/Library/Homebrew/extend/os/keg_relocate.rb +++ b/Library/Homebrew/extend/os/keg_relocate.rb @@ -1,2 +1 @@ -require "keg_relocate" require "extend/os/mac/keg_relocate" if OS.mac? diff --git a/Library/Homebrew/extend/os/mac/caveats.rb b/Library/Homebrew/extend/os/mac/caveats.rb index d912a83075..7ddfb5fb4d 100644 --- a/Library/Homebrew/extend/os/mac/caveats.rb +++ b/Library/Homebrew/extend/os/mac/caveats.rb @@ -1,4 +1,6 @@ class Caveats + undef plist_caveats + def plist_caveats s = [] if f.plist || (keg&.plist_installed?) diff --git a/Library/Homebrew/extend/os/mac/cleaner.rb b/Library/Homebrew/extend/os/mac/cleaner.rb index 74f627b48e..69d82814d7 100644 --- a/Library/Homebrew/extend/os/mac/cleaner.rb +++ b/Library/Homebrew/extend/os/mac/cleaner.rb @@ -1,6 +1,8 @@ class Cleaner private + undef executable_path? + def executable_path?(path) path.mach_o_executable? || path.text_executable? end diff --git a/Library/Homebrew/extend/os/mac/dependency_collector.rb b/Library/Homebrew/extend/os/mac/dependency_collector.rb index a7e5d7ffc8..543c2494ec 100644 --- a/Library/Homebrew/extend/os/mac/dependency_collector.rb +++ b/Library/Homebrew/extend/os/mac/dependency_collector.rb @@ -1,6 +1,10 @@ require "os/mac/ld64_dependency" class DependencyCollector + undef git_dep_if_needed, subversion_dep_if_needed, cvs_dep_if_needed, + xz_dep_if_needed, unzip_dep_if_needed, bzip2_dep_if_needed, + ld64_dep_if_needed + def git_dep_if_needed(tags) return if MacOS.version >= :lion Dependency.new("git", tags) @@ -18,7 +22,7 @@ class DependencyCollector Dependency.new("xz", tags) end - def zip_dep_if_needed(tags); end + def unzip_dep_if_needed(tags); end def bzip2_dep_if_needed(tags); end diff --git a/Library/Homebrew/extend/os/mac/development_tools.rb b/Library/Homebrew/extend/os/mac/development_tools.rb index d37e778ca5..ab2cfe90ea 100644 --- a/Library/Homebrew/extend/os/mac/development_tools.rb +++ b/Library/Homebrew/extend/os/mac/development_tools.rb @@ -3,10 +3,13 @@ require "os/mac/xcode" # @private class DevelopmentTools class << self - alias original_locate locate + alias generic_locate locate + undef installed?, default_compiler, curl_handles_most_https_certificates?, + subversion_handles_most_https_certificates? + def locate(tool) (@locate ||= {}).fetch(tool) do |key| - @locate[key] = if (located_tool = original_locate(tool)) + @locate[key] = if (located_tool = generic_locate(tool)) located_tool elsif MacOS.version > :tiger path = Utils.popen_read("/usr/bin/xcrun", "-no-cache", "-find", tool, err: :close).chomp @@ -22,6 +25,35 @@ class DevelopmentTools MacOS::Xcode.installed? || MacOS::CLT.installed? end + def default_compiler + case default_cc + # if GCC 4.2 is installed, e.g. via Tigerbrew, prefer it + # over the system's GCC 4.0 + when /^gcc-4\.0/ then gcc_4_2_build_version ? :gcc_4_2 : :gcc_4_0 + when /^gcc/ then :gcc_4_2 + when "clang" then :clang + else + # guess :( + if MacOS::Xcode.version >= "4.3" + :clang + else + :gcc_4_2 + end + end + end + + def curl_handles_most_https_certificates? + # The system Curl is too old for some modern HTTPS certificates on + # older macOS versions. + ENV["HOMEBREW_SYSTEM_CURL_TOO_OLD"].nil? + end + + def subversion_handles_most_https_certificates? + # The system Subversion is too old for some HTTPS certificates on + # older macOS versions. + MacOS.version >= :sierra + end + def installation_instructions if MacOS.version >= "10.9" <<~EOS @@ -64,34 +96,5 @@ class DevelopmentTools EOS end end - - def default_compiler - case default_cc - # if GCC 4.2 is installed, e.g. via Tigerbrew, prefer it - # over the system's GCC 4.0 - when /^gcc-4\.0/ then gcc_4_2_build_version ? :gcc_4_2 : :gcc_4_0 - when /^gcc/ then :gcc_4_2 - when "clang" then :clang - else - # guess :( - if MacOS::Xcode.version >= "4.3" - :clang - else - :gcc_4_2 - end - end - end - - def curl_handles_most_https_certificates? - # The system Curl is too old for some modern HTTPS certificates on - # older macOS versions. - ENV["HOMEBREW_SYSTEM_CURL_TOO_OLD"].nil? - end - - def subversion_handles_most_https_certificates? - # The system Subversion is too old for some HTTPS certificates on - # older macOS versions. - MacOS.version >= :sierra - end end end diff --git a/Library/Homebrew/extend/os/mac/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb index bb89b2367f..92fb3f315f 100644 --- a/Library/Homebrew/extend/os/mac/diagnostic.rb +++ b/Library/Homebrew/extend/os/mac/diagnostic.rb @@ -1,14 +1,14 @@ module Homebrew module Diagnostic class Checks + undef development_tools_checks, fatal_development_tools_checks, + build_error_checks + def development_tools_checks %w[ check_for_unsupported_macos - check_for_bad_install_name_tool check_for_installed_developer_tools check_xcode_license_approved - check_for_osx_gcc_installer - check_xcode_8_without_clt_on_el_capitan check_xcode_up_to_date check_clt_up_to_date check_for_other_package_managers @@ -92,20 +92,6 @@ module Homebrew EOS end - def check_xcode_8_without_clt_on_el_capitan - return unless MacOS::Xcode.without_clt? - # Scope this to Xcode 8 on El Cap for now - return unless MacOS.version == :el_capitan - return unless MacOS::Xcode.version >= "8" - - <<~EOS - You have Xcode 8 installed without the CLT; - this causes certain builds to fail on OS X El Capitan (10.11). - Please install the CLT via: - sudo xcode-select --install - EOS - end - def check_xcode_minimum_version return unless MacOS::Xcode.below_minimum_version? @@ -134,57 +120,6 @@ module Homebrew EOS end - def check_for_osx_gcc_installer - return unless MacOS.version < "10.7" || ((MacOS::Xcode.version || "0") > "4.1") - return unless DevelopmentTools.clang_version == "2.1" - - fix_advice = if MacOS.version >= :mavericks - "Please run `xcode-select --install` to install the CLT." - elsif MacOS.version >= :lion - "Please install the CLT or Xcode #{MacOS::Xcode.latest_version}." - else - "Please install Xcode #{MacOS::Xcode.latest_version}." - end - - <<~EOS - You seem to have osx-gcc-installer installed. - Homebrew doesn't support osx-gcc-installer. It causes many builds to fail and - is an unlicensed distribution of really old Xcode files. - #{fix_advice} - EOS - end - - def check_for_stray_developer_directory - # if the uninstaller script isn't there, it's a good guess neither are - # any troublesome leftover Xcode files - uninstaller = Pathname.new("/Developer/Library/uninstall-developer-folder") - return unless ((MacOS::Xcode.version || "0") >= "4.3") && uninstaller.exist? - - <<~EOS - You have leftover files from an older version of Xcode. - You should delete them using: - #{uninstaller} - EOS - end - - def check_for_bad_install_name_tool - return if MacOS.version < "10.9" - - libs = Pathname.new("/usr/bin/install_name_tool").dynamically_linked_libraries - - # otool may not work, for example if the Xcode license hasn't been accepted yet - return if libs.empty? - return if libs.include? "/usr/lib/libxcselect.dylib" - - <<~EOS - You have an outdated version of /usr/bin/install_name_tool installed. - This will cause binary package installations to fail. - This can happen if you install osx-gcc-installer or RailsInstaller. - To restore it, you must reinstall macOS or restore the binary from - the OS packages. - EOS - end - def check_for_other_package_managers ponk = MacOS.macports_or_fink return if ponk.empty? @@ -340,33 +275,6 @@ module Homebrew may not build correctly with a non-/usr/local prefix. EOS end - - def check_which_pkg_config - binary = which "pkg-config" - return if binary.nil? - - mono_config = Pathname.new("/usr/bin/pkg-config") - if mono_config.exist? && mono_config.realpath.to_s.include?("Mono.framework") - <<~EOS - You have a non-Homebrew 'pkg-config' in your PATH: - /usr/bin/pkg-config => #{mono_config.realpath} - - This was most likely created by the Mono installer. `./configure` may - have problems finding brew-installed packages using this other pkg-config. - - Mono no longer installs this file as of 3.0.4. You should - `sudo rm /usr/bin/pkg-config` and upgrade to the latest version of Mono. - EOS - elsif binary.to_s != "#{HOMEBREW_PREFIX}/bin/pkg-config" - <<~EOS - You have a non-Homebrew 'pkg-config' in your PATH: - #{binary} - - `./configure` may have problems finding brew-installed packages using - this other pkg-config. - EOS - end - end end end end diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb index 1a6d10f3b6..370bea2cf2 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb @@ -1,5 +1,39 @@ module Stdenv # @private + + undef homebrew_extra_pkg_config_paths, x11 + + def homebrew_extra_pkg_config_paths + ["#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}"] + end + + def x11 + # There are some config scripts here that should go in the PATH + append_path "PATH", MacOS::X11.bin.to_s + + # Append these to PKG_CONFIG_LIBDIR so they are searched + # *after* our own pkgconfig directories, as we dupe some of the + # libs in XQuartz. + append_path "PKG_CONFIG_LIBDIR", "#{MacOS::X11.lib}/pkgconfig" + append_path "PKG_CONFIG_LIBDIR", "#{MacOS::X11.share}/pkgconfig" + + append "LDFLAGS", "-L#{MacOS::X11.lib}" + append_path "CMAKE_PREFIX_PATH", MacOS::X11.prefix.to_s + append_path "CMAKE_INCLUDE_PATH", MacOS::X11.include.to_s + append_path "CMAKE_INCLUDE_PATH", "#{MacOS::X11.include}/freetype2" + + append "CPPFLAGS", "-I#{MacOS::X11.include}" + append "CPPFLAGS", "-I#{MacOS::X11.include}/freetype2" + + append_path "ACLOCAL_PATH", "#{MacOS::X11.share}/aclocal" + + if MacOS::XQuartz.provided_by_apple? && !MacOS::CLT.installed? + append_path "CMAKE_PREFIX_PATH", "#{MacOS.sdk_path}/usr/X11" + end + + append "CFLAGS", "-I#{MacOS::X11.include}" unless MacOS::CLT.installed? + end + def setup_build_environment(formula = nil) generic_setup_build_environment formula @@ -29,10 +63,6 @@ module Stdenv ld64 if Formula["ld64"].installed? end - def homebrew_extra_pkg_config_paths - ["#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}"] - end - # Sets architecture-specific flags for every environment variable # given in the list `flags`. # @private @@ -110,33 +140,6 @@ module Stdenv end end - def x11 - # There are some config scripts here that should go in the PATH - append_path "PATH", MacOS::X11.bin.to_s - - # Append these to PKG_CONFIG_LIBDIR so they are searched - # *after* our own pkgconfig directories, as we dupe some of the - # libs in XQuartz. - append_path "PKG_CONFIG_LIBDIR", "#{MacOS::X11.lib}/pkgconfig" - append_path "PKG_CONFIG_LIBDIR", "#{MacOS::X11.share}/pkgconfig" - - append "LDFLAGS", "-L#{MacOS::X11.lib}" - append_path "CMAKE_PREFIX_PATH", MacOS::X11.prefix.to_s - append_path "CMAKE_INCLUDE_PATH", MacOS::X11.include.to_s - append_path "CMAKE_INCLUDE_PATH", "#{MacOS::X11.include}/freetype2" - - append "CPPFLAGS", "-I#{MacOS::X11.include}" - append "CPPFLAGS", "-I#{MacOS::X11.include}/freetype2" - - append_path "ACLOCAL_PATH", "#{MacOS::X11.share}/aclocal" - - if MacOS::XQuartz.provided_by_apple? && !MacOS::CLT.installed? - append_path "CMAKE_PREFIX_PATH", "#{MacOS.sdk_path}/usr/X11" - end - - append "CFLAGS", "-I#{MacOS::X11.include}" unless MacOS::CLT.installed? - end - def no_weak_imports append "LDFLAGS", "-Wl,-no_weak_imports" if no_weak_imports_support? end diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index f233002ea0..c60c9ab193 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -1,16 +1,24 @@ module Superenv + class << self + undef bin + + # @private + def bin + return unless DevelopmentTools.installed? + + (HOMEBREW_SHIMS_PATH/"super").realpath + end + end + alias x11? x11 - # @private - def self.bin - return unless DevelopmentTools.installed? - - (HOMEBREW_SHIMS_PATH/"super").realpath - end - - def effective_sysroot - MacOS.sdk_path.to_s if MacOS::Xcode.without_clt? - end + undef homebrew_extra_paths, + homebrew_extra_pkg_config_paths, homebrew_extra_aclocal_paths, + homebrew_extra_isystem_paths, homebrew_extra_library_paths, + homebrew_extra_cmake_include_paths, + homebrew_extra_cmake_library_paths, + homebrew_extra_cmake_frameworks_paths, + determine_cccfg, set_x11_env_if_installed def homebrew_extra_paths paths = [] @@ -86,6 +94,14 @@ module Superenv s end + def effective_sysroot + MacOS.sdk_path.to_s if MacOS::Xcode.without_clt? + end + + def set_x11_env_if_installed + ENV.x11 = MacOS::X11.installed? + end + # @private def setup_build_environment(formula = nil) generic_setup_build_environment(formula) @@ -115,10 +131,6 @@ module Superenv self["HOMEBREW_PREFER_CLT_PROXIES"] = "1" if MacOS.version >= "10.9" end - def set_x11_env_if_installed - ENV.x11 = MacOS::X11.installed? - end - def no_weak_imports append "HOMEBREW_CCCFG", "w" if no_weak_imports_support? end diff --git a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb index 0b1a1643e1..1b43b0448b 100644 --- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb @@ -66,10 +66,10 @@ module FormulaCellarChecks keg = Keg.new(formula.prefix) checker = LinkageChecker.new(keg, formula) - return unless checker.broken_dylibs? + return unless checker.broken_library_linkage? output = <<~EOS #{formula} has broken dynamic library links: - #{checker.broken_dylibs.to_a * "\n "} + #{checker.display_test_output} EOS tab = Tab.for_keg(keg) if tab.poured_from_bottle diff --git a/Library/Homebrew/extend/os/mac/hardware/cpu.rb b/Library/Homebrew/extend/os/mac/hardware/cpu.rb index cc41ae9112..340e421221 100644 --- a/Library/Homebrew/extend/os/mac/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/mac/hardware/cpu.rb @@ -1,6 +1,9 @@ module Hardware class CPU class << self + undef optimization_flags, type, family, universal_archs, can_run?, + features, sse4? + PPC_OPTIMIZATION_FLAGS = { g3: "-mcpu=750", g4: "-mcpu=7400", @@ -8,6 +11,7 @@ module Hardware g5: "-mcpu=970", g5_64: "-mcpu=970 -arch ppc64", }.freeze + def optimization_flags OPTIMIZATION_FLAGS.merge(PPC_OPTIMIZATION_FLAGS) end @@ -71,10 +75,6 @@ module Hardware end end - def extmodel - sysctl_int("machdep.cpu.extmodel") - end - # Returns an array that's been extended with ArchitectureListExtension, # which provides helpers like #as_arch_flags and #as_cmake_arch_flags. def universal_archs @@ -113,6 +113,14 @@ module Hardware ).split(" ").map { |s| s.downcase.to_sym } end + def sse4? + sysctl_bool("hw.optional.sse4_1") + end + + def extmodel + sysctl_int("machdep.cpu.extmodel") + end + def aes? sysctl_bool("hw.optional.aes") end @@ -137,10 +145,6 @@ module Hardware sysctl_bool("hw.optional.supplementalsse3") end - def sse4? - sysctl_bool("hw.optional.sse4_1") - end - def sse4_2? sysctl_bool("hw.optional.sse4_2") end @@ -163,15 +167,15 @@ module Hardware def intel_can_run?(arch) case arch - when :ppc + when *PPC_32BIT_ARCHS # Rosetta is still available MacOS.version < :lion - when :ppc64 + when *PPC_64BIT_ARCHS # Rosetta never supported PPC64 false - when :x86_64 + when *INTEL_64BIT_ARCHS Hardware::CPU.is_64_bit? - when :i386 + when *INTEL_32BIT_ARCHS true else # dunno false @@ -180,9 +184,9 @@ module Hardware def ppc_can_run?(arch) case arch - when :ppc + when *PPC_32BIT_ARCHS true - when :ppc64 + when *PPC_64BIT_ARCHS Hardware::CPU.is_64_bit? else # Intel is never supported diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb index 707710be61..f92134e5a4 100644 --- a/Library/Homebrew/extend/os/mac/keg_relocate.rb +++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb @@ -1,24 +1,20 @@ class Keg - def fix_dynamic_linkage - mach_o_files.each do |file| - file.ensure_writable do - change_dylib_id(dylib_id_for(file), file) if file.dylib? + class << self + undef file_linked_libraries - each_install_name_for(file) do |bad_name| - # Don't fix absolute paths unless they are rooted in the build directory - next if bad_name.start_with?("/") && - !bad_name.start_with?(HOMEBREW_TEMP.to_s) && - !bad_name.start_with?(HOMEBREW_TEMP.realpath.to_s) - - new_name = fixed_name(file, bad_name) - change_install_name(bad_name, new_name, file) unless new_name == bad_name - end + def file_linked_libraries(file, string) + # Check dynamic library linkage. Importantly, do not perform for static + # libraries, which will falsely report "linkage" to themselves. + if file.mach_o_executable? || file.dylib? || file.mach_o_bundle? + file.dynamically_linked_libraries.select { |lib| lib.include? string } + else + [] end end - - generic_fix_dynamic_linkage end + undef relocate_dynamic_linkage, detect_cxx_stdlibs + def relocate_dynamic_linkage(relocation) mach_o_files.each do |file| file.ensure_writable do @@ -58,6 +54,26 @@ class Keg results.to_a end + def fix_dynamic_linkage + mach_o_files.each do |file| + file.ensure_writable do + change_dylib_id(dylib_id_for(file), file) if file.dylib? + + each_install_name_for(file) do |bad_name| + # Don't fix absolute paths unless they are rooted in the build directory + next if bad_name.start_with?("/") && + !bad_name.start_with?(HOMEBREW_TEMP.to_s) && + !bad_name.start_with?(HOMEBREW_TEMP.realpath.to_s) + + new_name = fixed_name(file, bad_name) + change_install_name(bad_name, new_name, file) unless new_name == bad_name + end + end + end + + generic_fix_dynamic_linkage + end + # If file is a dylib or bundle itself, look for the dylib named by # bad_name relative to the lib directory, so that we can skip the more # expensive recursive search if possible. @@ -130,14 +146,4 @@ class Keg # it's wrong. -O is a BSD-grep-only option. "-lrO" end - - def self.file_linked_libraries(file, string) - # Check dynamic library linkage. Importantly, do not perform for static - # libraries, which will falsely report "linkage" to themselves. - if file.mach_o_executable? || file.dylib? || file.mach_o_bundle? - file.dynamically_linked_libraries.select { |lib| lib.include? string } - else - [] - end - end end diff --git a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb index b8cf502a5e..b561d3c7af 100644 --- a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb @@ -4,26 +4,9 @@ class JavaRequirement < Requirement env_oracle_jdk || env_apple end - # A strict Java 8 requirement (1.8) should prompt the user to install - # 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 - # (*.0 not 1.*). - def cask - if @version.nil? || @version.to_s.end_with?("+") || - @version.to_f >= JAVA_CASK_MAP.keys.max.to_f - JAVA_CASK_MAP.fetch(JAVA_CASK_MAP.keys.max) - else - JAVA_CASK_MAP.fetch("1.8") - end - end - private - JAVA_CASK_MAP = { - "1.8" => "caskroom/versions/java8", - "10.0" => "java", - }.freeze + undef possible_javas, oracle_java_os def possible_javas javas = [] @@ -35,6 +18,10 @@ class JavaRequirement < Requirement javas end + def oracle_java_os + :darwin + end + def java_home_cmd return nil unless File.executable?("/usr/libexec/java_home") args = %w[--failfast] @@ -47,8 +34,4 @@ class JavaRequirement < Requirement def env_apple ENV.append_to_cflags "-I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/" end - - def oracle_java_os - :darwin - end end diff --git a/Library/Homebrew/extend/os/mac/requirements/non_binary_osxfuse_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/non_binary_osxfuse_requirement.rb new file mode 100644 index 0000000000..39d638cf88 --- /dev/null +++ b/Library/Homebrew/extend/os/mac/requirements/non_binary_osxfuse_requirement.rb @@ -0,0 +1,15 @@ +require "requirement" + +class NonBinaryOsxfuseRequirement < Requirement + fatal true + satisfy(build_env: false) do + HOMEBREW_PREFIX.to_s != "/usr/local" || !OsxfuseRequirement.binary_osxfuse_installed? + end + + def message + <<~EOS + osxfuse is already installed from the binary distribution and + conflicts with this formula. + EOS + end +end diff --git a/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb index 3f10a951ac..f6ca8cfc28 100644 --- a/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb @@ -1,7 +1,6 @@ require "requirement" class OsxfuseRequirement < Requirement - cask "osxfuse" download "https://osxfuse.github.io/" satisfy(build_env: false) { self.class.binary_osxfuse_installed? } @@ -20,15 +19,3 @@ class OsxfuseRequirement < Requirement end end end - -class NonBinaryOsxfuseRequirement < Requirement - fatal true - satisfy(build_env: false) { HOMEBREW_PREFIX.to_s != "/usr/local" || !OsxfuseRequirement.binary_osxfuse_installed? } - - def message - <<~EOS - osxfuse is already installed from the binary distribution and - conflicts with this formula. - EOS - end -end diff --git a/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb index 0c319d1de3..91fec032c3 100644 --- a/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb @@ -1,18 +1,17 @@ require "requirement" class X11Requirement < Requirement - cask "xquartz" - download "https://xquartz.macosforge.org" - - def min_version - MacOS::XQuartz.minimum_version - end - satisfy build_env: false do next false unless MacOS::XQuartz.installed? min_version <= MacOS::XQuartz.version end + undef min_version, message + + def min_version + MacOS::XQuartz.minimum_version + end + def message "XQuartz #{min_version} (or newer) is required to install this formula. #{super}" end diff --git a/Library/Homebrew/extend/os/mac/system_config.rb b/Library/Homebrew/extend/os/mac/system_config.rb index c0a28d3e95..20f04c0abd 100644 --- a/Library/Homebrew/extend/os/mac/system_config.rb +++ b/Library/Homebrew/extend/os/mac/system_config.rb @@ -1,27 +1,6 @@ class SystemConfig class << self - def xcode - if instance_variable_defined?(:@xcode) - @xcode - elsif MacOS::Xcode.installed? - @xcode = MacOS::Xcode.version.to_s - @xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix? - @xcode - end - end - - def clt - if instance_variable_defined?(:@clt) - @clt - elsif MacOS::CLT.installed? && MacOS::Xcode.version >= "4.3" - @clt = MacOS::CLT.version - end - end - - def macports_or_fink - @ponk ||= MacOS.macports_or_fink - @ponk.join(", ") unless @ponk.empty? - end + undef describe_java, describe_homebrew_ruby def describe_java # java_home doesn't exist on all macOSs; it might be missing on older versions. @@ -36,11 +15,6 @@ class SystemConfig javas.uniq.join(", ") end - def describe_xquartz - return "N/A" unless MacOS::XQuartz.installed? - "#{MacOS::XQuartz.version} => #{describe_path(MacOS::XQuartz.prefix)}" - end - def describe_homebrew_ruby s = describe_homebrew_ruby_version @@ -51,13 +25,32 @@ class SystemConfig end end + def xcode + @xcode ||= if MacOS::Xcode.installed? + xcode = MacOS::Xcode.version.to_s + xcode += " => #{MacOS::Xcode.prefix}" unless MacOS::Xcode.default_prefix? + xcode + end + end + + def clt + @clt ||= if MacOS::CLT.installed? && MacOS::Xcode.version >= "4.3" + MacOS::CLT.version + end + end + + def xquartz + @xquartz ||= if MacOS::XQuartz.installed? + "#{MacOS::XQuartz.version} => #{describe_path(MacOS::XQuartz.prefix)}" + end + end + def dump_verbose_config(f = $stdout) dump_generic_verbose_config(f) f.puts "macOS: #{MacOS.full_version}-#{kernel}" - f.puts "Xcode: #{xcode ? xcode : "N/A"}" f.puts "CLT: #{clt ? clt : "N/A"}" - f.puts "X11: #{describe_xquartz}" - f.puts "MacPorts/Fink: #{macports_or_fink}" if macports_or_fink + f.puts "Xcode: #{xcode ? xcode : "N/A"}" + f.puts "XQuartz: #{xquartz ? xquartz : "N/A"}" end end end diff --git a/Library/Homebrew/extend/os/mac/utils/bottles.rb b/Library/Homebrew/extend/os/mac/utils/bottles.rb index 03980aab0c..80d6afe78a 100644 --- a/Library/Homebrew/extend/os/mac/utils/bottles.rb +++ b/Library/Homebrew/extend/os/mac/utils/bottles.rb @@ -1,6 +1,8 @@ module Utils class Bottles class << self + undef tag + def tag if MacOS.version >= :lion MacOS.cat @@ -21,9 +23,10 @@ module Utils class Collector private - alias original_find_matching_tag find_matching_tag + alias generic_find_matching_tag find_matching_tag + def find_matching_tag(tag) - original_find_matching_tag(tag) || find_altivec_tag(tag) || find_or_later_tag(tag) + generic_find_matching_tag(tag) || find_altivec_tag(tag) || find_or_later_tag(tag) end # This allows generic Altivec PPC bottles to be supported in some diff --git a/Library/Homebrew/extend/os/missing_formula.rb b/Library/Homebrew/extend/os/missing_formula.rb index 02c59f4e4c..c589925764 100644 --- a/Library/Homebrew/extend/os/missing_formula.rb +++ b/Library/Homebrew/extend/os/missing_formula.rb @@ -1,2 +1 @@ -require "missing_formula" require "extend/os/mac/missing_formula" if OS.mac? diff --git a/Library/Homebrew/extend/os/requirements/java_requirement.rb b/Library/Homebrew/extend/os/requirements/java_requirement.rb index b512ada476..673d53079b 100644 --- a/Library/Homebrew/extend/os/requirements/java_requirement.rb +++ b/Library/Homebrew/extend/os/requirements/java_requirement.rb @@ -1,5 +1,3 @@ -require "requirements/java_requirement" - if OS.mac? require "extend/os/mac/requirements/java_requirement" elsif OS.linux? diff --git a/Library/Homebrew/extend/os/requirements/non_binary_osxfuse_requirement.rb b/Library/Homebrew/extend/os/requirements/non_binary_osxfuse_requirement.rb new file mode 100644 index 0000000000..099f29382c --- /dev/null +++ b/Library/Homebrew/extend/os/requirements/non_binary_osxfuse_requirement.rb @@ -0,0 +1,3 @@ +if OS.mac? + require "extend/os/mac/requirements/non_binary_osxfuse_requirement" +end diff --git a/Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb index 5f56d48c4a..ab491aa1e4 100644 --- a/Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb +++ b/Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb @@ -1,5 +1,3 @@ -require "requirements/osxfuse_requirement" - if OS.mac? require "extend/os/mac/requirements/osxfuse_requirement" elsif OS.linux? diff --git a/Library/Homebrew/extend/os/system_config.rb b/Library/Homebrew/extend/os/system_config.rb index fec31f1fa6..b80eec5e8e 100644 --- a/Library/Homebrew/extend/os/system_config.rb +++ b/Library/Homebrew/extend/os/system_config.rb @@ -1,5 +1,3 @@ -require "system_config" - if OS.mac? require "extend/os/mac/system_config" elsif OS.linux? diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index baf47b2764..ec7293496e 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -1,7 +1,5 @@ -require "pathname" require "resource" require "metafiles" -require "utils" module DiskUsageExtension def disk_usage @@ -368,7 +366,7 @@ class Pathname unless method_defined?(:/) def /(other) if !other.respond_to?(:to_str) && !other.respond_to?(:to_path) - odeprecated "Pathname#/ with #{other.class}", "a String or a Pathname" + odisabled "Pathname#/ with #{other.class}", "a String or a Pathname" end join(other.to_s) end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index c6af96f6d0..69c60a3d28 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -10,7 +10,6 @@ require "formulary" require "software_spec" require "install_renamed" require "pkg_version" -require "tap" require "keg" require "migrator" require "linkage_checker" @@ -174,7 +173,9 @@ class Formula @name = name @path = path @alias_path = alias_path - @alias_name = File.basename(alias_path) if alias_path + @alias_name = if alias_path + File.basename(alias_path) + end @revision = self.class.revision || 0 @version_scheme = self.class.version_scheme || 0 @@ -204,6 +205,7 @@ class Formula @pin = FormulaPin.new(self) @follow_installed_alias = true @prefix_returns_versioned_prefix = false + @oldname_lock = nil end # @private @@ -1130,7 +1132,7 @@ class Formula return false unless old_rack.directory? return false if old_rack.subdirs.empty? - tap == Tab.for_keg(old_rack.subdirs.sort.first).tap + tap == Tab.for_keg(old_rack.subdirs.min).tap end # @private @@ -1293,7 +1295,7 @@ class Formula # Avoid false positives for clock_gettime support on 10.11. # CMake cache entries for other weak symbols may be added here as needed. - if MacOS.version == "10.11" && MacOS::Xcode.installed? && MacOS::Xcode.version >= "8.0" + if MacOS.version == "10.11" && MacOS::Xcode.version >= "8.0" args << "-DHAVE_CLOCK_GETTIME:INTERNAL=0" end @@ -1539,10 +1541,10 @@ class Formula "desc" => desc, "homepage" => homepage, "oldname" => oldname, - "aliases" => aliases, + "aliases" => aliases.sort, "versions" => { "stable" => stable&.version&.to_s, - "bottle" => !bottle.nil?, + "bottle" => !bottle_specification.checksums.empty?, "devel" => devel&.version&.to_s, "head" => head&.version&.to_s, }, @@ -2364,7 +2366,7 @@ class Formula # version '4.8.1' # end def fails_with(compiler, &block) - odeprecated "fails_with :llvm" if compiler == :llvm + odisabled "fails_with :llvm" if compiler == :llvm specs.each { |spec| spec.fails_with(compiler, &block) } end diff --git a/Library/Homebrew/formula_cellar_checks.rb b/Library/Homebrew/formula_cellar_checks.rb index 471a5ea2fe..91a559dfad 100644 --- a/Library/Homebrew/formula_cellar_checks.rb +++ b/Library/Homebrew/formula_cellar_checks.rb @@ -154,6 +154,8 @@ module FormulaCellarChecks end def audit_installed + @new_formula ||= false + problem_if_output(check_manpages) problem_if_output(check_infopages) problem_if_output(check_jars) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 8c7efc978b..7ed473ee89 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1,5 +1,4 @@ require "cxxstdlib" -require "exceptions" require "formula" require "keg" require "tab" @@ -59,7 +58,8 @@ class FormulaInstaller @invalid_option_names = [] @requirement_messages = [] @poured_bottle = false - @pour_failed = false + @pour_failed = false + @start_time = nil end def self.attempted diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb index d44cf158fb..920db5839d 100644 --- a/Library/Homebrew/formula_support.rb +++ b/Library/Homebrew/formula_support.rb @@ -12,57 +12,27 @@ class KegOnlyReason end def valid? - case @reason - when :provided_pre_mountain_lion - MacOS.version < :mountain_lion - when :provided_pre_mavericks - MacOS.version < :mavericks - when :provided_pre_el_capitan - MacOS.version < :el_capitan - when :provided_pre_high_sierra - MacOS.version < :high_sierra - when :provided_until_xcode43 - MacOS::Xcode.installed? && MacOS::Xcode.version < "4.3" - when :provided_until_xcode5 - MacOS::Xcode.installed? && MacOS::Xcode.version < "5.0" - else - true - end + true end def to_s return @explanation unless @explanation.empty? case @reason - when :versioned_formula then <<~EOS - this is an alternate version of another formula - EOS - when :provided_by_macos then <<~EOS - macOS already provides this software and installing another version in - parallel can cause all kinds of trouble - EOS - when :shadowed_by_macos then <<~EOS - macOS provides similar software and installing this software in - parallel can cause all kinds of trouble - EOS - when :provided_pre_mountain_lion then <<~EOS - macOS already provides this software in versions before Mountain Lion - EOS - when :provided_pre_mavericks then <<~EOS - macOS already provides this software in versions before Mavericks - EOS - when :provided_pre_el_capitan then <<~EOS - macOS already provides this software in versions before El Capitan - EOS - when :provided_pre_high_sierra then <<~EOS - macOS already provides this software in versions before High Sierra - EOS - when :provided_until_xcode43 then <<~EOS - Xcode provides this software prior to version 4.3 - EOS - when :provided_until_xcode5 then <<~EOS - Xcode provides this software prior to version 5 - EOS + when :versioned_formula + <<~EOS + this is an alternate version of another formula + EOS + when :provided_by_macos + <<~EOS + macOS already provides this software and installing another version in + parallel can cause all kinds of trouble + EOS + when :shadowed_by_macos + <<~EOS + macOS provides similar software and installing this software in + parallel can cause all kinds of trouble + EOS else @reason end.strip @@ -87,10 +57,7 @@ class BottleDisableReason end def to_s - if unneeded? - "This formula doesn't require compiling." - else - @reason - end + return "This formula doesn't require compiling." if unneeded? + @reason end end diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 5f6ae0723b..508611ac80 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -1,5 +1,4 @@ require "digest/md5" -require "tap" require "extend/cachable" # The Formulary is responsible for creating instances of Formula. diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb index 32b5377a0e..5d641f1e26 100644 --- a/Library/Homebrew/global.rb +++ b/Library/Homebrew/global.rb @@ -1,20 +1,9 @@ -require "forwardable" -require "extend/module" -require "extend/predicable" -require "extend/fileutils" -require "extend/pathname" -require "extend/git_repository" -require "extend/ARGV" -require "PATH" -require "extend/string" -require "os" -require "utils" -require "exceptions" -require "set" -require "rbconfig" -require "official_taps" -require "pp" +require "pathname" require "English" +require "ostruct" + +require "pp" +require "extend/ARGV" ARGV.extend(HomebrewArgvExtension) @@ -23,9 +12,12 @@ HOMEBREW_VERSION = ENV["HOMEBREW_VERSION"] HOMEBREW_WWW = "https://brew.sh".freeze require "config" +require "extend/git_repository" HOMEBREW_REPOSITORY.extend(GitRepositoryExtension) +require "rbconfig" + RUBY_PATH = Pathname.new(RbConfig.ruby) RUBY_BIN = RUBY_PATH.dirname @@ -33,19 +25,22 @@ HOMEBREW_USER_AGENT_CURL = ENV["HOMEBREW_USER_AGENT_CURL"] HOMEBREW_USER_AGENT_RUBY = "#{ENV["HOMEBREW_USER_AGENT"]} ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}".freeze HOMEBREW_USER_AGENT_FAKE_SAFARI = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8".freeze -require "tap_constants" +require "extend/fileutils" module Homebrew extend FileUtils class << self - attr_writer :failed + attr_writer :failed, :raise_deprecation_exceptions, :auditing, :args def failed? + @failed ||= false @failed == true end - attr_writer :raise_deprecation_exceptions, :auditing + def args + @args ||= OpenStruct.new + end def raise_deprecation_exceptions? @raise_deprecation_exceptions == true @@ -60,7 +55,8 @@ end HOMEBREW_PULL_API_REGEX = %r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)} HOMEBREW_PULL_OR_COMMIT_URL_REGEX = %r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})] -require "compat" unless ARGV.include?("--no-compat") || ENV["HOMEBREW_NO_COMPAT"] +require "forwardable" +require "PATH" ENV["HOMEBREW_PATH"] ||= ENV["PATH"] ORIGINAL_PATHS = PATH.new(ENV["HOMEBREW_PATH"]).map do |p| @@ -88,3 +84,24 @@ HOMEBREW_INTERNAL_COMMAND_ALIASES = { "environment" => "--env", "--config" => "config", }.freeze + +require "set" + +require "os" +require "extend/pathname" + +require "extend/module" +require "extend/predicable" +require "extend/string" + +require "constants" +require "exceptions" +require "utils" + +require "official_taps" +require "tap" +require "tap_constants" + +if !ARGV.include?("--no-compat") && !ENV["HOMEBREW_NO_COMPAT"] + require "compat" +end diff --git a/Library/Homebrew/hardware.rb b/Library/Homebrew/hardware.rb index 0559ae694c..c7756dd3b5 100644 --- a/Library/Homebrew/hardware.rb +++ b/Library/Homebrew/hardware.rb @@ -1,10 +1,8 @@ -require "os" - module Hardware class CPU INTEL_32BIT_ARCHS = [:i386].freeze INTEL_64BIT_ARCHS = [:x86_64].freeze - PPC_32BIT_ARCHS = [:ppc, :ppc7400, :ppc7450, :ppc970].freeze + PPC_32BIT_ARCHS = [:ppc, :ppc32, :ppc7400, :ppc7450, :ppc970].freeze PPC_64BIT_ARCHS = [:ppc64].freeze class << self @@ -120,9 +118,9 @@ module Hardware if is_32_bit? arch_32_bit == arch elsif intel? - [:i386, :x86_64].include? arch + (INTEL_32BIT_ARCHS + INTEL_64BIT_ARCHS).include?(arch) elsif ppc? - [:ppc, :ppc64].include? arch + (PPC_32BIT_ARCHS + PPC_64BIT_ARCHS).include?(arch) else false end diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index 04c98c9556..02e318624b 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -1,4 +1,3 @@ -require "extend/pathname" require "keg_relocate" require "lock_file" require "ostruct" @@ -130,7 +129,7 @@ class Keg f_kegs = kegs_by_source[[f.name, f.tap]] next unless f_kegs - f_kegs.sort_by(&:version).last + f_kegs.max_by(&:version) end.compact next if required_kegs.empty? @@ -238,10 +237,14 @@ class Keg if tap bad_tap_opt = opt/tap.user - FileUtils.rm_rf bad_tap_opt if bad_tap_opt.directory? + if !bad_tap_opt.symlink? && bad_tap_opt.directory? + FileUtils.rm_rf bad_tap_opt + end end aliases.each do |a| + # versioned aliases are handled below + next if a =~ /.+@./ alias_symlink = opt/a if alias_symlink.symlink? && alias_symlink.exist? alias_symlink.delete if alias_symlink.realpath == opt_record.realpath @@ -251,7 +254,7 @@ class Keg end Pathname.glob("#{opt_record}@*").each do |a| - a = a.basename + a = a.basename.to_s next if aliases.include?(a) alias_symlink = opt/a diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index f70bbcbacd..6b996f6708 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -68,7 +68,7 @@ class Keg relocation.old_cellar => relocation.new_cellar, relocation.old_repository => relocation.new_repository, } - changed = s.gsub!(Regexp.union(replacements.keys), replacements) + changed = s.gsub!(Regexp.union(replacements.keys.sort_by(&:length).reverse), replacements) next unless changed changed_files += [first, *rest].map { |file| file.relative_path_from(path) } diff --git a/Library/Homebrew/language/python.rb b/Library/Homebrew/language/python.rb index de373efda4..171d7e8244 100644 --- a/Library/Homebrew/language/python.rb +++ b/Library/Homebrew/language/python.rb @@ -1,4 +1,3 @@ -require "utils" require "language/python_virtualenv_constants" module Language diff --git a/Library/Homebrew/language/python_virtualenv_constants.rb b/Library/Homebrew/language/python_virtualenv_constants.rb index 4efd2ce1d1..64d24166c0 100644 --- a/Library/Homebrew/language/python_virtualenv_constants.rb +++ b/Library/Homebrew/language/python_virtualenv_constants.rb @@ -1,2 +1,2 @@ -PYTHON_VIRTUALENV_URL = "https://files.pythonhosted.org/packages/d4/0c/9840c08189e030873387a73b90ada981885010dd9aea134d6de30cd24cb8/virtualenv-15.1.0.tar.gz".freeze -PYTHON_VIRTUALENV_SHA256 = "02f8102c2436bb03b3ee6dede1919d1dac8a427541652e5ec95171ec8adbc93a".freeze +PYTHON_VIRTUALENV_URL = "https://files.pythonhosted.org/packages/b1/72/2d70c5a1de409ceb3a27ff2ec007ecdd5cc52239e7c74990e32af57affe9/virtualenv-15.2.0.tar.gz".freeze +PYTHON_VIRTUALENV_SHA256 = "1d7e241b431e7afce47e77f8843a276f652699d1fa4f93b9d8ce0076fd7b0b54".freeze diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index f60cca98c1..6984397435 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -1,18 +1,14 @@ -require "set" require "keg" require "formula" class LinkageChecker - attr_reader :keg, :formula - attr_reader :brewed_dylibs, :system_dylibs, :broken_dylibs, :variable_dylibs - attr_reader :undeclared_deps, :unnecessary_deps, :reverse_links - def initialize(keg, formula = nil) @keg = keg @formula = formula || resolve_formula(keg) @brewed_dylibs = Hash.new { |h, k| h[k] = Set.new } @system_dylibs = Set.new - @broken_dylibs = Set.new + @broken_dylibs = [] + @broken_deps = Hash.new { |h, k| h[k] = [] } @variable_dylibs = Set.new @indirect_deps = [] @undeclared_deps = [] @@ -21,7 +17,51 @@ class LinkageChecker check_dylibs end + def display_normal_output + display_items "System libraries", @system_dylibs + display_items "Homebrew libraries", @brewed_dylibs + display_items "Indirect dependencies with linkage", @indirect_deps + display_items "Variable-referenced libraries", @variable_dylibs + display_items "Missing libraries", @broken_dylibs + display_items "Broken dependencies", @broken_deps + display_items "Undeclared dependencies with linkage", @undeclared_deps + display_items "Dependencies with no linkage", @unnecessary_deps + end + + def display_reverse_output + return if @reverse_links.empty? + sorted = @reverse_links.sort + sorted.each do |dylib, files| + puts dylib + files.each do |f| + unprefixed = f.to_s.strip_prefix "#{@keg}/" + puts " #{unprefixed}" + end + puts unless dylib == sorted.last[0] + end + end + + def display_test_output(puts_output: true) + display_items "Missing libraries", @broken_dylibs, puts_output: puts_output + display_items "Broken dependencies", @broken_deps, puts_output: puts_output + puts "No broken library linkage" unless broken_library_linkage? + end + + def broken_library_linkage? + !@broken_dylibs.empty? || !@broken_deps.empty? + end + + private + + attr_reader :keg, :formula + + def dylib_to_dep(dylib) + dylib =~ %r{#{Regexp.escape(HOMEBREW_PREFIX)}/(opt|Cellar)/([\w+-.@]+)/} + Regexp.last_match(2) + end + def check_dylibs + checked_dylibs = Set.new @keg.find do |file| next if file.symlink? || file.directory? next unless file.dylib? || file.binary_executable? || file.mach_o_bundle? @@ -30,6 +70,7 @@ class LinkageChecker # when checking for broken linkage file.dynamically_linked_libraries(except: :LC_LOAD_WEAK_DYLIB).each do |dylib| @reverse_links[dylib] << file + next if checked_dylibs.include? dylib if dylib.start_with? "@" @variable_dylibs << dylib else @@ -39,7 +80,11 @@ class LinkageChecker @system_dylibs << dylib rescue Errno::ENOENT next if harmless_broken_link?(dylib) - @broken_dylibs << dylib + if (dep = dylib_to_dep(dylib)) + @broken_deps[dep] |= [dylib] + else + @broken_dylibs << dylib + end else tap = Tab.for_keg(owner).tap f = if tap.nil? || tap.core_tap? @@ -50,6 +95,7 @@ class LinkageChecker @brewed_dylibs[f] << dylib end end + checked_dylibs << dylib end end @@ -94,6 +140,9 @@ class LinkageChecker @brewed_dylibs.keys.map { |x| x.split("/").last }.include?(name) end + missing_deps = @broken_deps.values.flatten.map { |d| dylib_to_dep(d) } + unnecessary_deps -= missing_deps + [indirect_deps, undeclared_deps, unnecessary_deps] end @@ -109,49 +158,6 @@ class LinkageChecker end end - def display_normal_output - display_items "System libraries", @system_dylibs - display_items "Homebrew libraries", @brewed_dylibs - display_items "Indirect dependencies with linkage", @indirect_deps - display_items "Variable-referenced libraries", @variable_dylibs - display_items "Missing libraries", @broken_dylibs - display_items "Undeclared dependencies with linkage", @undeclared_deps - display_items "Dependencies with no linkage", @unnecessary_deps - end - - def display_reverse_output - return if @reverse_links.empty? - sorted = @reverse_links.sort - sorted.each do |dylib, files| - puts dylib - files.each do |f| - unprefixed = f.to_s.strip_prefix "#{@keg}/" - puts " #{unprefixed}" - end - puts unless dylib == sorted.last[0] - end - end - - def display_test_output - display_items "Missing libraries", @broken_dylibs - display_items "Possible unnecessary dependencies", @unnecessary_deps - puts "No broken dylib links" if @broken_dylibs.empty? - end - - def broken_dylibs? - !@broken_dylibs.empty? - end - - def undeclared_deps? - !@undeclared_deps.empty? - end - - def unnecessary_deps? - !@unnecessary_deps.empty? - end - - private - # Whether or not dylib is a harmless broken link, meaning that it's # okay to skip (and not report) as broken. def harmless_broken_link?(dylib) @@ -165,20 +171,22 @@ class LinkageChecker # Display a list of things. # Things may either be an array, or a hash of (label -> array) - def display_items(label, things) + def display_items(label, things, puts_output: true) return if things.empty? - puts "#{label}:" + output = "#{label}:" if things.is_a? Hash - things.sort.each do |list_label, list| - list.sort.each do |item| - puts " #{item} (#{list_label})" + things.keys.sort.each do |list_label| + things[list_label].sort.each do |item| + output += "\n #{item} (#{list_label})" end end else things.sort.each do |item| - puts " #{item}" + output += "\n #{item}" end end + puts output if puts_output + output end def resolve_formula(keg) diff --git a/Library/Homebrew/manpages/brew.1.md.erb b/Library/Homebrew/manpages/brew.1.md.erb index a4854cc67c..3d54243a3d 100644 --- a/Library/Homebrew/manpages/brew.1.md.erb +++ b/Library/Homebrew/manpages/brew.1.md.erb @@ -102,6 +102,8 @@ can take several different forms: The formula file will be cached for later use. ## ENVIRONMENT +Note that environment variables must have a value set to be detected. For example, `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just `export HOMEBREW_NO_INSECURE_REDIRECT`. + * `HOMEBREW_ARTIFACT_DOMAIN`: If set, instructs Homebrew to use the given URL as a download mirror for bottles and binaries. @@ -136,6 +138,10 @@ can take several different forms: *Default:* `~/Library/Caches/Homebrew`. + * `HOMEBREW_CURLRC`: + If set, Homebrew will not pass `-q` when invoking `curl`(1) (which disables + the use of `curlrc`). + * `HOMEBREW_CURL_VERBOSE`: If set, Homebrew will pass `--verbose` when invoking `curl`(1). diff --git a/Library/Homebrew/metafiles.rb b/Library/Homebrew/metafiles.rb index 96fa086f49..51d64ad8d0 100644 --- a/Library/Homebrew/metafiles.rb +++ b/Library/Homebrew/metafiles.rb @@ -1,4 +1,3 @@ -require "set" module Metafiles # https://github.com/github/markup#markups diff --git a/Library/Homebrew/migrator.rb b/Library/Homebrew/migrator.rb index 503f889852..9b295c1a43 100644 --- a/Library/Homebrew/migrator.rb +++ b/Library/Homebrew/migrator.rb @@ -1,4 +1,3 @@ -require "formula" require "lock_file" require "keg" require "tab" diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb index 31dfa94efa..3b4682d668 100644 --- a/Library/Homebrew/missing_formula.rb +++ b/Library/Homebrew/missing_formula.rb @@ -1,6 +1,4 @@ require "formulary" -require "tap" -require "utils" module Homebrew module MissingFormula @@ -95,7 +93,7 @@ module Homebrew new_tap = old_tap.tap_migrations[name] next unless new_tap - new_tap_user, new_tap_repo, = new_tap.split("/") + new_tap_user, new_tap_repo, new_tap_new_name = new_tap.split("/") new_tap_name = "#{new_tap_user}/#{new_tap_repo}" message = <<~EOS @@ -103,9 +101,18 @@ module Homebrew EOS break if new_tap_name == CoreTap.instance.name + install_cmd = if new_tap_user == "caskroom" + "cask install" + else + "install" + end + new_tap_new_name ||= name + message += <<~EOS You can access it again by running: brew tap #{new_tap_name} + And then you can install it by running: + brew #{install_cmd} #{new_tap_new_name} EOS break end diff --git a/Library/Homebrew/official_taps.rb b/Library/Homebrew/official_taps.rb index 7eace302a5..a6c7b00fba 100644 --- a/Library/Homebrew/official_taps.rb +++ b/Library/Homebrew/official_taps.rb @@ -1,7 +1,3 @@ -OFFICIAL_TAPS = %w[ - php -].freeze - OFFICIAL_CASK_TAPS = %w[ cask versions @@ -25,6 +21,7 @@ DEPRECATED_OFFICIAL_TAPS = %w[ gui head-only nginx + php python science tex diff --git a/Library/Homebrew/options.rb b/Library/Homebrew/options.rb index 05dd643ffe..11f8df3a54 100644 --- a/Library/Homebrew/options.rb +++ b/Library/Homebrew/options.rb @@ -1,4 +1,3 @@ -require "set" class Option attr_reader :name, :description, :flag diff --git a/Library/Homebrew/os.rb b/Library/Homebrew/os.rb index cc6c865375..ed12ea734f 100644 --- a/Library/Homebrew/os.rb +++ b/Library/Homebrew/os.rb @@ -1,5 +1,3 @@ -require "rbconfig" - module OS def self.mac? return false if ENV["HOMEBREW_TEST_GENERIC_OS"] diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index ade801c42a..3088dbf265 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -1,5 +1,3 @@ -require "hardware" -require "development_tools" require "os/mac/version" require "os/mac/xcode" require "os/mac/xquartz" @@ -211,6 +209,8 @@ module OS "9.0" => { clang: "9.0", clang_build: 900 }, "9.0.1" => { clang: "9.0", clang_build: 900 }, "9.1" => { clang: "9.0", clang_build: 900 }, + "9.2" => { clang: "9.0", clang_build: 900 }, + "9.3" => { clang: "9.1", clang_build: 902 }, }.freeze def compilers_standard? diff --git a/Library/Homebrew/os/mac/architecture_list.rb b/Library/Homebrew/os/mac/architecture_list.rb index 6f498c51f6..6373aed44d 100644 --- a/Library/Homebrew/os/mac/architecture_list.rb +++ b/Library/Homebrew/os/mac/architecture_list.rb @@ -1,4 +1,4 @@ -require "extend/os/hardware" +require "hardware" module ArchitectureListExtension # @private diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index 2e4ec63819..f39273b42d 100644 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -18,12 +18,12 @@ module OS when "10.10" then "7.2.1" when "10.11" then "8.2.1" when "10.12" then "9.2" - when "10.13" then "9.2" + when "10.13" then "9.3" else raise "macOS '#{MacOS.version}' is invalid" unless OS::Mac.prerelease? # Default to newest known version of Xcode for unreleased macOS versions. - "9.2" + "9.3" end end @@ -169,8 +169,9 @@ module OS when 73 then "7.3" when 80 then "8.0" when 81 then "8.3" - when 90 then "9.0" - else "9.0" + when 90 then "9.2" + when 91 then "9.3" + else "9.3" end end @@ -221,7 +222,7 @@ module OS # on the older supported platform for that Xcode release, i.e there's no # CLT package for 10.11 that contains the Clang version from Xcode 8. case MacOS.version - when "10.13" then "900.0.39.2" + when "10.13" then "902.0.39.1" when "10.12" then "900.0.39.2" when "10.11" then "800.0.42.1" when "10.10" then "700.1.81" diff --git a/Library/Homebrew/patch.rb b/Library/Homebrew/patch.rb index 77021480c4..9150be25e7 100644 --- a/Library/Homebrew/patch.rb +++ b/Library/Homebrew/patch.rb @@ -17,6 +17,8 @@ module Patch else ExternalPatch.new(strip, &block) end + when nil + raise ArgumentError, "nil value for strip" else raise ArgumentError, "unexpected value #{strip.inspect} for strip" end diff --git a/Library/Homebrew/readall.rb b/Library/Homebrew/readall.rb index 1b6ae016e0..249987b33b 100644 --- a/Library/Homebrew/readall.rb +++ b/Library/Homebrew/readall.rb @@ -1,5 +1,4 @@ require "formula" -require "tap" module Readall class << self diff --git a/Library/Homebrew/requirement.rb b/Library/Homebrew/requirement.rb index f70746c316..d922a22772 100644 --- a/Library/Homebrew/requirement.rb +++ b/Library/Homebrew/requirement.rb @@ -140,7 +140,7 @@ class Requirement attr_rw :fatal, :cask, :download def default_formula(_val = nil) - odeprecated "Requirement.default_formula" + odisabled "Requirement.default_formula" end def satisfy(options = nil, &block) diff --git a/Library/Homebrew/requirements/java_requirement.rb b/Library/Homebrew/requirements/java_requirement.rb index 213203ff39..27348fa8cc 100644 --- a/Library/Homebrew/requirements/java_requirement.rb +++ b/Library/Homebrew/requirements/java_requirement.rb @@ -4,6 +4,20 @@ class JavaRequirement < Requirement fatal true download "https://www.oracle.com/technetwork/java/javase/downloads/index.html" + # A strict Java 8 requirement (1.8) should prompt the user to install + # 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 + # (*.0 not 1.*). + def cask + if @version.nil? || @version.to_s.end_with?("+") || + @version.to_f >= JAVA_CASK_MAP.keys.max.to_f + JAVA_CASK_MAP.fetch(JAVA_CASK_MAP.keys.max) + else + JAVA_CASK_MAP.fetch("1.8") + end + end + satisfy build_env: false do setup_java next false unless @java @@ -42,6 +56,11 @@ class JavaRequirement < Requirement private + JAVA_CASK_MAP = { + "1.8" => "caskroom/versions/java8", + "10.0" => "java", + }.freeze + def version_without_plus if exact_version? @version diff --git a/Library/Homebrew/requirements/non_binary_osxfuse_requirement.rb b/Library/Homebrew/requirements/non_binary_osxfuse_requirement.rb new file mode 100644 index 0000000000..bb7788f487 --- /dev/null +++ b/Library/Homebrew/requirements/non_binary_osxfuse_requirement.rb @@ -0,0 +1,7 @@ +require "requirement" + +class NonBinaryOsxfuseRequirement < Requirement + fatal false +end + +require "extend/os/requirements/non_binary_osxfuse_requirement" diff --git a/Library/Homebrew/requirements/osxfuse_requirement.rb b/Library/Homebrew/requirements/osxfuse_requirement.rb index 9a07209d43..2e67a4b050 100644 --- a/Library/Homebrew/requirements/osxfuse_requirement.rb +++ b/Library/Homebrew/requirements/osxfuse_requirement.rb @@ -1,11 +1,8 @@ require "requirement" class OsxfuseRequirement < Requirement + cask "osxfuse" fatal true end -class NonBinaryOsxfuseRequirement < Requirement - fatal false -end - require "extend/os/requirements/osxfuse_requirement" diff --git a/Library/Homebrew/requirements/x11_requirement.rb b/Library/Homebrew/requirements/x11_requirement.rb index 65ce6396fb..6ffcc2db71 100644 --- a/Library/Homebrew/requirements/x11_requirement.rb +++ b/Library/Homebrew/requirements/x11_requirement.rb @@ -5,6 +5,9 @@ class X11Requirement < Requirement fatal true + cask "xquartz" + download "https://xquartz.macosforge.org" + env { ENV.x11 } def initialize(name = "x11", tags = []) diff --git a/Library/Homebrew/rubocops/components_order_cop.rb b/Library/Homebrew/rubocops/components_order_cop.rb index a1a576177b..912f4d3804 100644 --- a/Library/Homebrew/rubocops/components_order_cop.rb +++ b/Library/Homebrew/rubocops/components_order_cop.rb @@ -2,7 +2,7 @@ require_relative "./extend/formula_cop" module RuboCop module Cop - module FormulaAuditStrict + module FormulaAudit # This cop checks for correct order of components in a Formula # # - component_precedence_list has component hierarchy in a nested list @@ -62,8 +62,14 @@ module RuboCop end end + # `aspell`: options and resources should be grouped by language + WHITELIST = %w[ + aspell + ].freeze + # Method to format message for reporting component precedence violations def component_problem(c1, c2) + return if WHITELIST.include?(@formula_name) problem "`#{format_component(c1)}` (line #{line_number(c1)}) should be put before `#{format_component(c2)}` (line #{line_number(c2)})" end diff --git a/Library/Homebrew/rubocops/components_redundancy_cop.rb b/Library/Homebrew/rubocops/components_redundancy_cop.rb index 7495b986b7..e22ec6a910 100644 --- a/Library/Homebrew/rubocops/components_redundancy_cop.rb +++ b/Library/Homebrew/rubocops/components_redundancy_cop.rb @@ -2,7 +2,7 @@ require_relative "./extend/formula_cop" module RuboCop module Cop - module FormulaAuditStrict + module FormulaAudit # This cop checks if redundant components are present and other component errors # # - `url|checksum|mirror` should be inside `stable` block diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb index ae343a9fc2..55f22bbc61 100644 --- a/Library/Homebrew/rubocops/extend/formula_cop.rb +++ b/Library/Homebrew/rubocops/extend/formula_cop.rb @@ -99,6 +99,17 @@ module RuboCop end end + # Returns array of function call nodes matching func_name in every descendant of node + # Ex. function call: foo(*args, **kwargs) + # Does not match method calls: foo.bar(*args, **kwargs) + # Returns every function calls if no func_name is passed + def find_every_func_call_by_name(node, func_name = nil) + return if node.nil? + node.each_descendant(:send).select do |func_node| + func_node.receiver.nil? && (func_name.nil? || func_name == func_node.method_name) + end + end + # Given a method_name and arguments, yields to a block with # matching method passed as a parameter to the block def find_method_with_args(node, method_name, *args) diff --git a/Library/Homebrew/rubocops/urls_cop.rb b/Library/Homebrew/rubocops/urls_cop.rb index 4ef801689d..30420a793a 100644 --- a/Library/Homebrew/rubocops/urls_cop.rb +++ b/Library/Homebrew/rubocops/urls_cop.rb @@ -6,8 +6,8 @@ module RuboCop # This cop audits urls and mirrors in Formulae class Urls < FormulaCop def audit_formula(_node, _class_node, _parent_class_node, body_node) - urls = find_every_method_call_by_name(body_node, :url) - mirrors = find_every_method_call_by_name(body_node, :mirror) + urls = find_every_func_call_by_name(body_node, :url) + mirrors = find_every_func_call_by_name(body_node, :mirror) # GNU urls; doesn't apply to mirrors gnu_pattern = %r{^(?:https?|ftp)://ftpmirror.gnu.org/(.*)} @@ -191,12 +191,11 @@ module RuboCop end end end - end - module FormulaAuditStrict + class PyPiUrls < FormulaCop def audit_formula(_node, _class_node, _parent_class_node, body_node) - urls = find_every_method_call_by_name(body_node, :url) - mirrors = find_every_method_call_by_name(body_node, :mirror) + urls = find_every_func_call_by_name(body_node, :url) + mirrors = find_every_func_call_by_name(body_node, :mirror) urls += mirrors # Check pypi urls diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index df7b86770c..ce3cac8064 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -42,6 +42,7 @@ class SoftwareSpec @deprecated_options = [] @build = BuildOptions.new(Options.create(@flags), options) @compiler_failures = [] + @bottle_disable_reason = nil end def owner=(owner) @@ -127,9 +128,9 @@ class SoftwareSpec def option(name, description = "") opt = PREDEFINED_OPTIONS.fetch(name) do if name.is_a?(Symbol) - odeprecated "passing arbitrary symbols (i.e. #{name.inspect}) to `option`" - name = name.to_s + odisabled "passing arbitrary symbols (i.e. #{name.inspect}) to `option`" end + unless name.is_a?(String) raise ArgumentError, "option name must be string or symbol; got a #{name.class}: #{name}" end @@ -204,7 +205,7 @@ class SoftwareSpec end def fails_with(compiler, &block) - odeprecated "fails_with :llvm" if compiler == :llvm + odisabled "fails_with :llvm" if compiler == :llvm compiler_failures << CompilerFailure.create(compiler, &block) end diff --git a/Library/Homebrew/system_config.rb b/Library/Homebrew/system_config.rb index 13867e7d4e..f42572add0 100644 --- a/Library/Homebrew/system_config.rb +++ b/Library/Homebrew/system_config.rb @@ -1,27 +1,10 @@ require "hardware" require "software_spec" require "rexml/document" -require "tap" require "development_tools" class SystemConfig class << self - def gcc_4_2 - @gcc_4_2 ||= if DevelopmentTools.installed? - DevelopmentTools.gcc_4_2_build_version - else - Version::NULL - end - end - - def gcc_4_0 - @gcc_4_0 ||= if DevelopmentTools.installed? - DevelopmentTools.gcc_4_0_build_version - else - Version::NULL - end - end - def clang @clang ||= if DevelopmentTools.installed? DevelopmentTools.clang_version @@ -72,42 +55,6 @@ class SystemConfig end end - def describe_perl - describe_path(which("perl", ENV["HOMEBREW_PATH"])) - end - - def describe_python - python = begin - python_path = PATH.new(ENV["HOMEBREW_PATH"]) - .prepend(Formula["python"].opt_libexec/"bin") - which "python", python_path - rescue FormulaUnavailableError - which "python" - end - - return "N/A" if python.nil? - python_binary = Utils.popen_read python, "-c", "import sys; sys.stdout.write(sys.executable)" - python_binary = Pathname.new(python_binary).realpath - if python == python_binary - python - else - "#{python} => #{python_binary}" - end - end - - def describe_ruby - ruby = which "ruby", ENV["HOMEBREW_PATH"] - return "N/A" if ruby.nil? - ruby_binary = Utils.popen_read ruby, "-rrbconfig", "-e", \ - 'include RbConfig;print"#{CONFIG["bindir"]}/#{CONFIG["ruby_install_name"]}#{CONFIG["EXEEXT"]}"' - ruby_binary = Pathname.new(ruby_binary).realpath - if ruby == ruby_binary - ruby - else - "#{ruby} => #{ruby_binary}" - end - end - def describe_homebrew_ruby_version case RUBY_VERSION when /^1\.[89]/, /^2\.0/ @@ -168,6 +115,7 @@ class SystemConfig HOMEBREW_REPOSITORY: "/usr/local/Homebrew", HOMEBREW_CELLAR: "/usr/local/Cellar", HOMEBREW_CACHE: "#{ENV["HOME"]}/Library/Caches/Homebrew", + HOMEBREW_RUBY_WARNINGS: "-W0", }.freeze boring_keys = %w[ HOMEBREW_BROWSER @@ -183,7 +131,6 @@ class SystemConfig HOMEBREW_LIBRARY HOMEBREW_MACOS_VERSION HOMEBREW_RUBY_PATH - HOMEBREW_RUBY_WARNINGS HOMEBREW_SYSTEM HOMEBREW_OS_VERSION HOMEBREW_PATH @@ -203,17 +150,20 @@ class SystemConfig 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 = "set" if key =~ /(cookie|key|token|password)/i - f.puts "#{key}: #{value}" + if defaults_hash[:HOMEBREW_RUBY_WARNINGS] != ENV["HOMEBREW_RUBY_WARNINGS"].to_s + f.puts "HOMEBREW_RUBY_WARNINGS: #{ENV["HOMEBREW_RUBY_WARNINGS"]}" + end + unless ENV["HOMEBREW_ENV"] + 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 = "set" if key =~ /(cookie|key|token|password)/i + f.puts "#{key}: #{value}" + end end f.puts hardware if hardware 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.print "Clang: " if clang.null? f.puts "N/A" @@ -227,9 +177,6 @@ class SystemConfig end f.puts "Git: #{describe_git}" f.puts "Curl: #{describe_curl}" - f.puts "Perl: #{describe_perl}" - f.puts "Python: #{describe_python}" - f.puts "Ruby: #{describe_ruby}" f.puts "Java: #{describe_java}" end alias dump_generic_verbose_config dump_verbose_config diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index e13b9af754..bcd205bab8 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -1,4 +1,3 @@ -require "extend/string" require "extend/cachable" require "readall" @@ -78,6 +77,8 @@ class Tap @full_name = "#{@user}/homebrew-#{@repo}" @path = TAP_DIRECTORY/@full_name.downcase @path.extend(GitRepositoryExtension) + @alias_table = nil + @alias_reverse_table = nil end # clear internal cache @@ -200,7 +201,9 @@ class Tap # install this {Tap}. # # @param [Hash] options - # @option options [String] :clone_targe If passed, it will be used as the clone remote. + # @option options [String] :clone_target If passed, it will be used as the clone remote. + # @option options [Boolean, nil] :force_auto_update If present, whether to override the + # logic that skips non-GitHub repositories during auto-updates. # @option options [Boolean] :full_clone If set as true, full clone will be used. # @option options [Boolean] :quiet If set, suppress all output. def install(options = {}) @@ -209,12 +212,14 @@ class Tap full_clone = options.fetch(:full_clone, false) quiet = options.fetch(:quiet, false) requested_remote = options[:clone_target] || default_remote + # if :force_auto_update is unset, use nil, meaning "no change" + force_auto_update = options.fetch(:force_auto_update, nil) if official? && DEPRECATED_OFFICIAL_TAPS.include?(repo) odie "#{name} was deprecated. This tap is now empty as all its formulae were migrated." end - if installed? + if installed? && force_auto_update.nil? raise TapAlreadyTappedError, name unless full_clone raise TapAlreadyUnshallowError, name unless shallow? end @@ -223,6 +228,11 @@ class Tap Utils.ensure_git_installed! if installed? + unless force_auto_update.nil? + config["forceautoupdate"] = force_auto_update + return if !full_clone || !shallow? + end + if options[:clone_target] && requested_remote != remote raise TapRemoteMismatchError.new(name, @remote, requested_remote) end @@ -258,6 +268,8 @@ class Tap raise end + config["forceautoupdate"] = force_auto_update unless force_auto_update.nil? + link_completions_and_manpages formula_count = formula_files.size diff --git a/Library/Homebrew/test/Gemfile.lock b/Library/Homebrew/test/Gemfile.lock index b69a5f0a71..f5b13e4fbf 100644 --- a/Library/Homebrew/test/Gemfile.lock +++ b/Library/Homebrew/test/Gemfile.lock @@ -12,7 +12,7 @@ GEM parallel (1.12.1) parallel_tests (2.21.2) parallel - parser (2.5.0.2) + parser (2.5.0.5) ast (~> 2.4.0) powerpack (0.1.1) rainbow (3.0.0) @@ -36,7 +36,7 @@ GEM rspec-support (3.7.1) rspec-wait (0.0.9) rspec (>= 3, < 4) - rubocop (0.53.0) + rubocop (0.55.0) parallel (~> 1.10) parser (>= 2.5) powerpack (~> 0.1) @@ -62,7 +62,7 @@ DEPENDENCIES rspec-its rspec-retry rspec-wait - rubocop (= 0.53.0) + rubocop (= 0.55.0) simplecov BUNDLED WITH diff --git a/Library/Homebrew/test/PATH_spec.rb b/Library/Homebrew/test/PATH_spec.rb index 68233c23c7..b6f884d665 100644 --- a/Library/Homebrew/test/PATH_spec.rb +++ b/Library/Homebrew/test/PATH_spec.rb @@ -23,6 +23,13 @@ describe PATH do it "returns a PATH array" do expect(described_class.new("/path1", "/path2").to_ary).to eq(["/path1", "/path2"]) end + + it "does not allow mutating the original" do + path = described_class.new("/path1", "/path2") + path.to_ary << "/path3" + + expect(path).not_to include("/path3") + end end describe "#to_str" do @@ -61,6 +68,12 @@ describe PATH do end end + describe "#==" do + it "always returns false when comparing against something which does not respons to `#to_ary` or `#to_str`" do + expect(described_class.new).not_to eq Object.new + end + end + describe "#include?" do it "returns true if a path is included" do path = described_class.new("/path1", "/path2") diff --git a/Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb b/Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb index 7e12854760..5502d83ed7 100644 --- a/Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb +++ b/Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb @@ -19,7 +19,7 @@ describe Hbc::Artifact::Artifact, :cask do context "without target" do it "fails to load" do expect { - Hbc::CaskLoader.load(cask_path("with-generic-artifact-no-target")) + Hbc::CaskLoader.load(cask_path("invalid/invalid-generic-artifact-no-target")) }.to raise_error(Hbc::CaskInvalidError, /target required for Generic Artifact/) end end diff --git a/Library/Homebrew/test/cask/artifact/two_apps_incorrect_spec.rb b/Library/Homebrew/test/cask/artifact/two_apps_incorrect_spec.rb deleted file mode 100644 index cda5b4488c..0000000000 --- a/Library/Homebrew/test/cask/artifact/two_apps_incorrect_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -describe Hbc::Artifact::App, :cask do - # FIXME: Doesn't actually raise because the `app` stanza is not evaluated on load. - # it "must raise" do - # lambda { - # Hbc::CaskLoader.load(cask_path("with-two-apps-incorrect")) - # }.must_raise - # # TODO: later give the user a nice exception for this case and check for it here - # end -end diff --git a/Library/Homebrew/test/cask/cask_spec.rb b/Library/Homebrew/test/cask/cask_spec.rb index e8d5aff8f8..4b9393d6cc 100644 --- a/Library/Homebrew/test/cask/cask_spec.rb +++ b/Library/Homebrew/test/cask/cask_spec.rb @@ -70,14 +70,6 @@ describe Hbc::Cask, :cask do end end - describe "all_tokens" do - it "returns a token for every Cask" do - all_cask_tokens = Hbc.all_tokens - expect(all_cask_tokens.count).to be > 20 - all_cask_tokens.each { |token| expect(token).to be_kind_of(String) } - end - end - describe "metadata" do it "proposes a versioned metadata directory name for each instance" do cask_token = "local-caffeine" diff --git a/Library/Homebrew/test/cask/cli/audit_spec.rb b/Library/Homebrew/test/cask/cli/audit_spec.rb index da8bf12737..2ed4ea9f11 100644 --- a/Library/Homebrew/test/cask/cli/audit_spec.rb +++ b/Library/Homebrew/test/cask/cli/audit_spec.rb @@ -7,9 +7,7 @@ describe Hbc::CLI::Audit, :cask do describe "selection of Casks to audit" do it "audits all Casks if no tokens are given" do - expect(cask).to be_a Hbc::Cask - - allow(Hbc).to receive(:all).and_return([cask, cask]) + allow(Hbc::Cask).to receive(:to_a).and_return([cask, cask]) expect(Hbc::Auditor).to receive(:audit).twice.and_return(true) diff --git a/Library/Homebrew/test/cask/cli/style_spec.rb b/Library/Homebrew/test/cask/cli/style_spec.rb index aaf3248f17..6f486ea939 100644 --- a/Library/Homebrew/test/cask/cli/style_spec.rb +++ b/Library/Homebrew/test/cask/cli/style_spec.rb @@ -83,11 +83,13 @@ describe Hbc::CLI::Style, :cask do context "when no cask tokens are given" do let(:tokens) { [] } - before do - allow(Hbc).to receive(:all_tapped_cask_dirs).and_return(%w[Casks MoreCasks]) + matcher :a_path_ending_with do |end_string| + match do |actual| + expect(actual.to_s).to end_with(end_string) + end end - it { is_expected.to eq(%w[Casks MoreCasks]) } + it { is_expected.to contain_exactly(a_path_ending_with("/caskroom/homebrew-spec/Casks"), a_path_ending_with("/third-party/homebrew-tap/Casks")) } end context "when at least one cask token is a path that exists" do diff --git a/Library/Homebrew/test/cask/dsl_spec.rb b/Library/Homebrew/test/cask/dsl_spec.rb index 3e16b915ea..0348daab13 100644 --- a/Library/Homebrew/test/cask/dsl_spec.rb +++ b/Library/Homebrew/test/cask/dsl_spec.rb @@ -72,7 +72,7 @@ describe Hbc::DSL, :cask do end context "when it contains a deprecated DSL version", :needs_compat do - let(:token) { "with-dsl-version" } + let(:token) { "compat/with-dsl-version" } it "may use deprecated DSL version hash syntax" do allow(ENV).to receive(:[]).with("HOMEBREW_DEVELOPER").and_return(nil) diff --git a/Library/Homebrew/test/cask/scopes_spec.rb b/Library/Homebrew/test/cask/scopes_spec.rb deleted file mode 100644 index d1c03b9b0c..0000000000 --- a/Library/Homebrew/test/cask/scopes_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -describe Hbc::Scopes, :cask do - describe "installed" do - it "returns a list installed Casks by loading Casks for all the dirs that exist in the caskroom" do - allow(Hbc::CaskLoader).to receive(:load) { |token| "loaded-#{token}" } - - Hbc.caskroom.join("cask-bar").mkpath - Hbc.caskroom.join("cask-foo").mkpath - - installed_casks = Hbc.installed - - expect(Hbc::CaskLoader).to have_received(:load).with("cask-bar") - expect(Hbc::CaskLoader).to have_received(:load).with("cask-foo") - expect(installed_casks).to eq( - %w[ - loaded-cask-bar - loaded-cask-foo - ], - ) - end - - it "optimizes performance by resolving to a fully qualified path before calling Hbc::CaskLoader.load" do - fake_tapped_cask_dir = Pathname.new(Dir.mktmpdir).join("Casks") - absolute_path_to_cask = fake_tapped_cask_dir.join("some-cask.rb") - - allow(Hbc::CaskLoader).to receive(:load) - allow(Hbc).to receive(:all_tapped_cask_dirs) { [fake_tapped_cask_dir] } - - Hbc.caskroom.join("some-cask").mkdir - fake_tapped_cask_dir.mkdir - FileUtils.touch(absolute_path_to_cask) - - Hbc.installed - - expect(Hbc::CaskLoader).to have_received(:load).with(absolute_path_to_cask) - end - end -end diff --git a/Library/Homebrew/test/cleanup_spec.rb b/Library/Homebrew/test/cleanup_spec.rb index 9ec3a30479..40ab4280b7 100644 --- a/Library/Homebrew/test/cleanup_spec.rb +++ b/Library/Homebrew/test/cleanup_spec.rb @@ -1,7 +1,6 @@ require "test/support/fixtures/testball" require "cleanup" require "fileutils" -require "pathname" describe Homebrew::Cleanup do let(:ds_store) { Pathname.new("#{HOMEBREW_PREFIX}/Library/.DS_Store") } diff --git a/Library/Homebrew/test/cli_parser_spec.rb b/Library/Homebrew/test/cli_parser_spec.rb index 037f007a27..5f65a80c15 100644 --- a/Library/Homebrew/test/cli_parser_spec.rb +++ b/Library/Homebrew/test/cli_parser_spec.rb @@ -16,24 +16,25 @@ describe Homebrew::CLI::Parser do } it "parses short option" do - args = parser.parse(["-v"]) - expect(args).to be_verbose + parser.parse(["-v"]) + expect(Homebrew.args).to be_verbose end it "parses a single valid option" do - args = parser.parse(["--verbose"]) - expect(args).to be_verbose + parser.parse(["--verbose"]) + expect(Homebrew.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] + expect(Homebrew.args).to be_verbose + expect(args).to eq %w[--verbose 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(Homebrew.args).to be_verbose expect(args.more_verbose?).to be nil end @@ -50,8 +51,8 @@ describe Homebrew::CLI::Parser do 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" + flag "--filename=", description: "Name of the file" + comma_array "--files", description: "Comma separated filenames" end } @@ -60,7 +61,7 @@ describe Homebrew::CLI::Parser do expect(args.filename).to eq "random.txt" end - it "raises an exception when a flag's required arg is not passed" do + it "raises an exception when a flag's required value is not passed" do expect { parser.parse(["--filename"]) }.to raise_error(OptionParser::MissingArgument, /--filename/) end diff --git a/Library/Homebrew/test/cmd/linkapps_spec.rb b/Library/Homebrew/test/cmd/linkapps_spec.rb deleted file mode 100644 index 8fc0d5eb91..0000000000 --- a/Library/Homebrew/test/cmd/linkapps_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -describe "brew linkapps", :integration_test do - let(:home_dir) { mktmpdir } - let(:apps_dir) { home_dir/"Applications" } - - it "symlinks applications" do - apps_dir.mkpath - - setup_test_formula "testball" - - source_app = HOMEBREW_CELLAR/"testball/0.1/TestBall.app" - source_app.mkpath - - ENV.delete "HOMEBREW_DEVELOPER" - - expect { brew "linkapps", "--local", "HOME" => home_dir } - .to output(/Linking: #{Regexp.escape(source_app)}/).to_stdout - .and output(/'brew linkapps' is deprecated/).to_stderr - .and be_a_success - - expect(apps_dir/"TestBall.app").to be_a_symlink - end -end diff --git a/Library/Homebrew/test/cmd/missing_spec.rb b/Library/Homebrew/test/cmd/missing_spec.rb index f84dd66567..4c1b4367a8 100644 --- a/Library/Homebrew/test/cmd/missing_spec.rb +++ b/Library/Homebrew/test/cmd/missing_spec.rb @@ -14,7 +14,7 @@ describe "brew missing", :integration_test do expect { brew "missing" } .to output("foo\n").to_stdout .and not_to_output.to_stderr - .and be_a_success + .and be_a_failure end it "prints nothing if all dependencies are installed" do @@ -35,7 +35,7 @@ describe "brew missing", :integration_test do expect { brew "missing", "--hide=foo" } .to output("bar: foo\n").to_stdout .and not_to_output.to_stderr - .and be_a_success + .and be_a_failure end end end diff --git a/Library/Homebrew/test/cmd/search_spec.rb b/Library/Homebrew/test/cmd/search_spec.rb index c55a51e4fe..15c66cba31 100644 --- a/Library/Homebrew/test/cmd/search_spec.rb +++ b/Library/Homebrew/test/cmd/search_spec.rb @@ -1,7 +1,6 @@ describe "brew search", :integration_test do before do setup_test_formula "testball" - setup_remote_tap "caskroom/cask" end it "lists all available Formulae when no argument is given" do @@ -26,6 +25,8 @@ describe "brew search", :integration_test do end it "falls back to a GitHub tap search when no formula is found", :needs_network, retry: 3 do + setup_remote_tap "caskroom/cask" + expect { brew "search", "caskroom/cask/firefox" } .to output(/firefox/).to_stdout .and output(/Searching/).to_stderr diff --git a/Library/Homebrew/test/cmd/switch_spec.rb b/Library/Homebrew/test/cmd/switch_spec.rb index 48d7dcdd08..fbf44810b9 100644 --- a/Library/Homebrew/test/cmd/switch_spec.rb +++ b/Library/Homebrew/test/cmd/switch_spec.rb @@ -1,7 +1,7 @@ describe "brew switch", :integration_test do it "allows switching between Formula versions" do expect { brew "switch" } - .to output(/Usage: brew switch /).to_stderr + .to output(/Usage: brew switch /).to_stderr .and not_to_output.to_stdout .and be_a_failure @@ -25,7 +25,7 @@ describe "brew switch", :integration_test do .and be_a_success expect { brew "switch", "testball", "0.3" } - .to output("Versions available: 0.1, 0.2\n").to_stdout + .to output("testball installed versions: 0.1, 0.2\n").to_stdout .and output(/testball does not have a version "0.3"/).to_stderr .and be_a_failure end diff --git a/Library/Homebrew/test/cmd/unlinkapps_spec.rb b/Library/Homebrew/test/cmd/unlinkapps_spec.rb deleted file mode 100644 index 397a8ec5e2..0000000000 --- a/Library/Homebrew/test/cmd/unlinkapps_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -describe "brew unlinkapps", :integration_test do - let(:home_dir) { mktmpdir } - let(:apps_dir) { home_dir/"Applications" } - - it "unlinks symlinked applications" do - apps_dir.mkpath - - setup_test_formula "testball" - - source_app = HOMEBREW_CELLAR/"testball/0.1/TestBall.app" - source_app.mkpath - - FileUtils.ln_s source_app, apps_dir/"TestBall.app" - - ENV.delete "HOMEBREW_DEVELOPER" - - expect { brew "unlinkapps", "--local", "HOME" => home_dir } - .to output(%r{Unlinking: #{Regexp.escape(apps_dir)}/TestBall.app}).to_stdout - .and output(/'brew unlinkapps' is deprecated/).to_stderr - .and be_a_success - end -end diff --git a/Library/Homebrew/test/dev-cmd/audit_spec.rb b/Library/Homebrew/test/dev-cmd/audit_spec.rb index c9264f22b5..83b3ad215a 100644 --- a/Library/Homebrew/test/dev-cmd/audit_spec.rb +++ b/Library/Homebrew/test/dev-cmd/audit_spec.rb @@ -8,596 +8,598 @@ module Count end end -describe FormulaText do - alias_matcher :have_data, :be_data - alias_matcher :have_end, :be_end - alias_matcher :have_trailing_newline, :be_trailing_newline +module Homebrew + describe FormulaText do + alias_matcher :have_data, :be_data + alias_matcher :have_end, :be_end + alias_matcher :have_trailing_newline, :be_trailing_newline - let(:dir) { mktmpdir } + let(:dir) { mktmpdir } - def formula_text(name, body = nil, options = {}) - path = dir/"#{name}.rb" + def formula_text(name, body = nil, options = {}) + path = dir/"#{name}.rb" - path.write <<~EOS - class #{Formulary.class_s(name)} < Formula - #{body} + path.write <<~EOS + class #{Formulary.class_s(name)} < Formula + #{body} + end + #{options[:patch]} + EOS + + described_class.new(path) + end + + specify "simple valid Formula" do + ft = formula_text "valid", <<~EOS + url "http://www.example.com/valid-1.0.tar.gz" + EOS + + expect(ft).not_to have_data + expect(ft).not_to have_end + expect(ft).to have_trailing_newline + + expect(ft =~ /\burl\b/).to be_truthy + expect(ft.line_number(/desc/)).to be nil + expect(ft.line_number(/\burl\b/)).to eq(2) + expect(ft).to include("Valid") + end + + specify "#trailing_newline?" do + ft = formula_text "newline" + expect(ft).to have_trailing_newline + end + + specify "#data?" do + ft = formula_text "data", <<~EOS + patch :DATA + EOS + + expect(ft).to have_data + end + + specify "#end?" do + ft = formula_text "end", "", patch: "__END__\na patch here" + expect(ft).to have_end + expect(ft.without_patch).to eq("class End < Formula\n \nend") + end + end + + describe FormulaAuditor do + def formula_auditor(name, text, options = {}) + path = Pathname.new "#{dir}/#{name}.rb" + path.open("w") do |f| + f.write text end - #{options[:patch]} - EOS - described_class.new(path) - end - - specify "simple valid Formula" do - ft = formula_text "valid", <<~EOS - url "http://www.example.com/valid-1.0.tar.gz" - EOS - - expect(ft).not_to have_data - expect(ft).not_to have_end - expect(ft).to have_trailing_newline - - expect(ft =~ /\burl\b/).to be_truthy - expect(ft.line_number(/desc/)).to be nil - expect(ft.line_number(/\burl\b/)).to eq(2) - expect(ft).to include("Valid") - end - - specify "#trailing_newline?" do - ft = formula_text "newline" - expect(ft).to have_trailing_newline - end - - specify "#data?" do - ft = formula_text "data", <<~EOS - patch :DATA - EOS - - expect(ft).to have_data - end - - specify "#end?" do - ft = formula_text "end", "", patch: "__END__\na patch here" - expect(ft).to have_end - expect(ft.without_patch).to eq("class End < Formula\n \nend") - end -end - -describe FormulaAuditor do - def formula_auditor(name, text, options = {}) - path = Pathname.new "#{dir}/#{name}.rb" - path.open("w") do |f| - f.write text + described_class.new(Formulary.factory(path), options) end - described_class.new(Formulary.factory(path), options) - end + let(:dir) { mktmpdir } - let(:dir) { mktmpdir } + describe "#problems" do + it "is empty by default" do + fa = formula_auditor "foo", <<~EOS + class Foo < Formula + url "http://example.com/foo-1.0.tgz" + end + EOS - describe "#problems" do - it "is empty by default" do - fa = formula_auditor "foo", <<~EOS - class Foo < Formula - url "http://example.com/foo-1.0.tgz" - end - EOS - - expect(fa.problems).to be_empty - end - end - - describe "#audit_file" do - specify "file permissions" do - allow(File).to receive(:umask).and_return(022) - - fa = formula_auditor "foo", <<~EOS - class Foo < Formula - url "http://example.com/foo-1.0.tgz" - end - EOS - - path = fa.formula.path - path.chmod 0400 - - fa.audit_file - expect(fa.problems) - .to eq(["Incorrect file permissions (400): chmod 644 #{path}"]) + expect(fa.problems).to be_empty + end end - specify "DATA but no __END__" do - fa = formula_auditor "foo", <<~EOS - class Foo < Formula - url "http://example.com/foo-1.0.tgz" - patch :DATA - end - EOS + describe "#audit_file" do + specify "file permissions" do + allow(File).to receive(:umask).and_return(022) - fa.audit_file - expect(fa.problems).to eq(["'DATA' was found, but no '__END__'"]) + fa = formula_auditor "foo", <<~EOS + class Foo < Formula + url "http://example.com/foo-1.0.tgz" + end + EOS + + path = fa.formula.path + path.chmod 0400 + + fa.audit_file + expect(fa.problems) + .to eq(["Incorrect file permissions (400): chmod 644 #{path}"]) + end + + specify "DATA but no __END__" do + fa = formula_auditor "foo", <<~EOS + class Foo < Formula + url "http://example.com/foo-1.0.tgz" + patch :DATA + end + EOS + + fa.audit_file + expect(fa.problems).to eq(["'DATA' was found, but no '__END__'"]) + end + + specify "__END__ but no DATA" do + fa = formula_auditor "foo", <<~EOS + class Foo < Formula + url "http://example.com/foo-1.0.tgz" + end + __END__ + a patch goes here + EOS + + fa.audit_file + expect(fa.problems).to eq(["'__END__' was found, but 'DATA' is not used"]) + end + + specify "no trailing newline" do + fa = formula_auditor "foo", 'class Foo -Note that pinned, outdated formulae that are depended on by another formula will be upgraded when required as we do not allow formulae to be built against non-latest versions. +Note that pinned, outdated formulae that are depended on by another formula need to be upgraded when required as we do not allow formulae to be built against non-latest versions. ## How do I uninstall old versions of a formula? By default, Homebrew does not uninstall old versions of a formula, so @@ -55,7 +55,7 @@ and run `./uninstall --help` to view more uninstall options. ## How do I uninstall a formula? If you do not uninstall all of the versions that Homebrew has installed, Homebrew will continue to attempt to install the newest version it knows -about when you run `brew upgrade --all`. This can be surprising. +about when you run `brew upgrade`. This can be surprising. To remove a formula entirely, you may run `brew uninstall formula_name --force`. @@ -125,9 +125,9 @@ Or: fix this for Homebrew formulae (although we don’t always test for it), but you’ll find that many RubyGems and Python setup scripts break which is something outside our control. -3. **It’s safe**
Apple has left this directory for us. Which means - there is no `/usr/local` directory by default, so there - is no need to worry about messing up existing tools. +3. **It’s safe**
Apple has assigned this directory for non-system utilities. Which means + there is no files in `/usr/local` by default, so there + is no need to worry about messing up existing or system tools. **If you plan to install gems that depend on brews then save yourself a bunch of hassle and install to @@ -139,21 +139,16 @@ It is not always straightforward to tell `gem` to look in non-standard directori **tl;dr** Sudo is dangerous, and you installed TextMate.app without sudo anyway. -Homebrew is designed to work without using sudo. You can decide to use -it but we strongly recommend not to do so. If you have used sudo and run -into a bug then this is likely to be the cause. Please don’t file a bug -report unless you can reproduce it after reinstalling Homebrew from -scratch without using sudo. +Homebrew refuses to work using sudo. -You should only ever sudo a tool you trust. Of course, you can trust -Homebrew ;) But do you trust the multi-megabyte Makefile that Homebrew -runs? Developers often understand C++ far better than they understand -make syntax. It’s too high a risk to sudo such stuff. It could break -your base system, or alter it subtly. +You should only ever sudo a tool you trust. Of course, you can trust Homebrew +;) But do you trust the multi-megabyte Makefile that Homebrew runs? Developers +often understand C++ far better than they understand make syntax. It’s too high +a risk to sudo such stuff. It could modify (or upload) any files on your +system.And indeed, we’ve seen some build scripts try to modify `/usr` even when +the prefix was specified as something else entirely. -And indeed, we’ve seen some build scripts try to modify -`/usr` even when the prefix was specified as something else -entirely. +We use the macOS sandbox to stop this but this doesn't work when run as the `root` user (which also has read and write access to almost everything on the system). Did you `chown root /Applications/TextMate.app`? Probably not. So is it that important to `chown root wget`? diff --git a/docs/Formula-Cookbook.md b/docs/Formula-Cookbook.md index 3f6902409a..37237265d7 100644 --- a/docs/Formula-Cookbook.md +++ b/docs/Formula-Cookbook.md @@ -31,7 +31,6 @@ Before submitting a new formula make sure your package: * meets all our [Acceptable Formulae](Acceptable-Formulae.md) requirements * isn't already in Homebrew (check `brew search `) -* isn't in another official [Homebrew tap](https://github.com/Homebrew) * isn't already waiting to be merged (check the [issue tracker](https://github.com/Homebrew/homebrew-core/pulls)) * is still supported by upstream (i.e. doesn't require extensive patching) * has a stable, tagged version (i.e. not just a GitHub repository with no versions) diff --git a/docs/How-To-Open-a-Homebrew-Pull-Request.md b/docs/How-To-Open-a-Homebrew-Pull-Request.md index 812d990e08..16b1234940 100644 --- a/docs/How-To-Open-a-Homebrew-Pull-Request.md +++ b/docs/How-To-Open-a-Homebrew-Pull-Request.md @@ -25,8 +25,6 @@ Depending on the change you want to make, you need to send the pull request to t 3. Add your pushable forked repository with `git remote add https://github.com//homebrew-core.git` * `` is your GitHub username, not your local machine username. -For formulae in central taps other than `homebrew/core`, such as `homebrew/php`, substitute that tap's name for `homebrew/core` in each step, and alter the GitHub repository URLs as necessary. - ## Create your pull request from a new branch To make a new branch and submit it for review, create a GitHub pull request with the following steps: diff --git a/docs/How-to-Create-and-Maintain-a-Tap.md b/docs/How-to-Create-and-Maintain-a-Tap.md index 610380aa60..76b0bbda67 100644 --- a/docs/How-to-Create-and-Maintain-a-Tap.md +++ b/docs/How-to-Create-and-Maintain-a-Tap.md @@ -16,7 +16,7 @@ repository’s root, or under `Formula` or `HomebrewFormula` subdirectories. We recommend the latter options because it makes the repository organisation easier to grasp, and top-level files are not mixed with formulae. -See [homebrew/php](https://github.com/Homebrew/homebrew-php) for an example of +See [homebrew/core](https://github.com/Homebrew/homebrew-core) for an example of a tap with a `Formula` subdirectory. ### Installing diff --git a/docs/Installation.md b/docs/Installation.md index 9f091d2e58..f186b546e1 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -11,7 +11,7 @@ it does it too. And you have to confirm everything it will do before it starts. ## Requirements * An Intel CPU [1](#1) -* OS X 10.10 or higher [2](#2) +* OS X 10.11 or higher [2](#2) * Command Line Tools (CLT) for Xcode: `xcode-select --install`, [developer.apple.com/downloads](https://developer.apple.com/downloads) or [Xcode](https://itunes.apple.com/us/app/xcode/id497799835) [3](#3) @@ -19,11 +19,16 @@ it does it too. And you have to confirm everything it will do before it starts. ## Alternative Installs +### OS X Lion 10.7 and below + +Using the instructions on https://brew.sh or below whenever you call `curl` you must pass `--insecure` as an argument. This is because your system `curl` is too old to speak to GitHub using HTTPS. Don't worry, on the first `brew update` Homebrew will install a newer, more secure `curl` for your machine. + ### Untar anywhere Just extract (or `git clone`) Homebrew wherever you want. Just avoid: * Directories with names that contain spaces. Homebrew itself can handle spaces, but many build scripts cannot. +* `/tmp` subdirectories because Homebrew gets upset * `/sw` and `/opt/local` because build scripts get confused when Homebrew is there instead of Fink or MacPorts, respectively. However do yourself a favor and install to `/usr/local`. Some things may @@ -46,7 +51,7 @@ you can assume you will have trouble if you don’t conform. Also, you can find PowerPC and Tiger branches from other users in the fork network. See [Interesting Taps and Forks](Interesting-Taps-and-Forks.md). -2 10.10 or higher is recommended. 10.5–10.9 are +2 10.11 or higher is recommended. 10.5–10.10 are supported on a best-effort basis. For 10.4 see [Tigerbrew](https://github.com/mistydemeo/tigerbrew). diff --git a/docs/Interesting-Taps-and-Forks.md b/docs/Interesting-Taps-and-Forks.md index 4d569e6c05..57f0730b72 100644 --- a/docs/Interesting-Taps-and-Forks.md +++ b/docs/Interesting-Taps-and-Forks.md @@ -3,15 +3,9 @@ A _tap_ is homebrew-speak for a Git repository containing extra formulae. Homebrew has the capability to add (and remove) multiple taps to your local installation with the `brew tap` and `brew untap` commands. Type `man brew` in your Terminal. The main repository [https://github.com/Homebrew/homebrew-core](https://github.com/Homebrew/homebrew-core), often called `homebrew/core`, is always built-in. -## Main taps +Your taps are Git repositories located at `$(brew --repository)/Library/Taps`. -* [homebrew/php](https://github.com/Homebrew/homebrew-php): Repository for PHP-related formulae. - -`brew search` looks in these taps as well as in [homebrew/core](https://github.com/Homebrew/homebrew-core) so don't worry about missing stuff. - -You can be added as a maintainer for one of the Homebrew organization taps and aid the project! If you are interested please feel free to ask in an issue or pull request after submitting multiple high-quality pull requests. We want your help! - -## Other interesting taps +## Unsupported interesting taps * [denji/nginx](https://github.com/denji/homebrew-nginx): A tap for NGINX modules, intended for its `nginx-full` formula which includes more module options. @@ -37,12 +31,8 @@ You can be added as a maintainer for one of the Homebrew organization taps and a * [lifepillar/appleii](https://github.com/lifepillar/homebrew-appleii): Formulae for vintage Apple emulation. -## Interesting forks +## Unsupported interesting forks * [mistydemeo/tigerbrew](https://github.com/mistydemeo/tigerbrew): Experimental Tiger PowerPC version. * [Linuxbrew/brew](https://github.com/Linuxbrew/brew): Experimental Linux version. - -## Technical details - -Your taps are Git repositories located at `$(brew --repository)/Library/Taps`. diff --git a/docs/Maintainer-Guidelines.md b/docs/Maintainer-Guidelines.md index 1d69f53811..34d046a4bb 100644 --- a/docs/Maintainer-Guidelines.md +++ b/docs/Maintainer-Guidelines.md @@ -104,3 +104,14 @@ Whitespace corrections (to Ruby standard etc.) are allowed (in fact this is a good opportunity to do it) provided the line itself has some kind of modification that is not whitespace in it. But be careful about making changes to inline patches—make sure they still apply. + +## Communication +Maintainers have a variety of ways to communicate with each other: + +- Homebrew's public repositories on GitHub +- Homebrew's group communications between more than two maintainers on private channels (e.g. GitHub/Slack/Discourse) +- Homebrew's direct 1:1 messages between two maintainers on private channels (e.g. iMessage/Slack/Discourse/IRC/carrier pigeon) + +All communication should ideally occur in public on GitHub. Where this is not possible or appropriate (e.g. a security disclosure, interpersonal issue between two maintainers, urgent breakage that needs to be resolved) this can move to maintainers' private group communication and, if necessary, 1:1 communication. Technical decisions should not happen in 1:1 communications but if they do (or did in the past) they must end up back as something linkable on GitHub. For example, if a technical decision was made a year ago on Slack and another maintainer/contributor/user asks about it on GitHub, that's a good chance to explain it to them and have something that can be linked to in the future. + +This makes it easier for other maintainers, contributors and users to follow along with what we're doing (and, more importantly, why we're doing it) and means that decisions have a linkable URL. diff --git a/docs/Manpage.md b/docs/Manpage.md index 3479ec771d..86baa20206 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -340,6 +340,8 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note If `--hide=``hidden` is passed, act as if none of `hidden` are installed. `hidden` should be a comma-separated list of formulae. + `missing` exits with a non-zero status if any formulae are missing dependencies. + * `options` [`--compact`] (`--all`|`--installed`|`formulae`): Display install options specific to `formulae`. @@ -378,9 +380,7 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note * `prune` [`--dry-run`]: Remove dead symlinks from the Homebrew prefix. This is generally not - needed, but can be useful when doing DIY installations. Also remove broken - app symlinks from `/Applications` and `~/Applications` that were previously - created by `brew linkapps`. + needed, but can be useful when doing DIY installations. If `--dry-run` or `-n` is passed, show what would be removed, but do not actually remove anything. @@ -444,13 +444,13 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note Exits with a non-zero status if any style violations are found. - * `switch` `name` `version`: - Symlink all of the specific `version` of `name`'s install to Homebrew prefix. + * `switch` `formula` `version`: + Symlink all of the specific `version` of `formula`'s install to Homebrew prefix. * `tap`: List all installed taps. - * `tap` [`--full`] `user``/``repo` [`URL`]: + * `tap` [`--full`] [`--force-auto-update`] `user``/``repo` [`URL`]: Tap a formula repository. With `URL` unspecified, taps a formula repository from GitHub using HTTPS. @@ -467,6 +467,10 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note if `--full` is passed, a full clone will be used. To convert a shallow copy to a full copy, you can retap passing `--full` without first untapping. + By default, only taps hosted on GitHub are auto-updated (for performance + reasons). If `--force-auto-update` is passed, this tap will be auto-updated + even if it is not hosted on GitHub. + `tap` is re-runnable and exits successfully if there's nothing to do. However, retapping with a different `URL` will cause an exception, so first `untap` if you need to modify the `URL`. @@ -474,9 +478,6 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note * `tap` `--repair`: Migrate tapped formulae from symlink-based to directory-based structure. - * `tap` `--list-official`: - List all official taps. - * `tap` `--list-pinned`: List all pinned taps. @@ -669,7 +670,7 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note `audit` exits with a non-zero status if any errors are found. This is useful, for instance, for implementing pre-commit hooks. - * `bottle` [`--verbose`] [`--no-rebuild`|`--keep-old`] [`--skip-relocation`] [`--root-url=``URL`] [`--force-core-tap`] `formulae`: + * `bottle` [`--verbose`] [`--no-rebuild`|`--keep-old`] [`--skip-relocation`] [`--or-later`] [`--root-url=``URL`] [`--force-core-tap`] `formulae`: Generate a bottle (binary package) from a formula installed with `--build-bottle`. @@ -686,6 +687,8 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note If `--root-url` is passed, use the specified `URL` as the root of the bottle's URL instead of Homebrew's default. + If `--or-later` is passed, append _or_later to the bottle tag. + If `--force-core-tap` is passed, build a bottle even if `formula` is not in homebrew/core or any installed taps. @@ -853,7 +856,7 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note * `release-notes` [`--markdown`] [`previous_tag`] [`end_ref`]: Output the merged pull requests on Homebrew/brew between two Git refs. - If no `previous_tag` is provided it defaults to the newest tag. + If no `previous_tag` is provided it defaults to the latest tag. If no `end_ref` is provided it defaults to `origin/master`. If `--markdown` is passed, output as a Markdown list. @@ -1079,6 +1082,8 @@ can take several different forms: The formula file will be cached for later use. ## ENVIRONMENT +Note that environment variables must have a value set to be detected. For example, `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just `export HOMEBREW_NO_INSECURE_REDIRECT`. + * `HOMEBREW_ARTIFACT_DOMAIN`: If set, instructs Homebrew to use the given URL as a download mirror for bottles and binaries. @@ -1113,6 +1118,10 @@ can take several different forms: *Default:* `~/Library/Caches/Homebrew`. + * `HOMEBREW_CURLRC`: + If set, Homebrew will not pass `-q` when invoking `curl`(1) (which disables + the use of `curlrc`). + * `HOMEBREW_CURL_VERBOSE`: If set, Homebrew will pass `--verbose` when invoking `curl`(1). diff --git a/docs/New-Maintainer-Checklist.md b/docs/New-Maintainer-Checklist.md index cb4919d697..628437e2ea 100644 --- a/docs/New-Maintainer-Checklist.md +++ b/docs/New-Maintainer-Checklist.md @@ -55,7 +55,7 @@ If they accept, follow a few steps to get them set up: - Add them to the [Jenkins' GitHub Authorization Settings admin user names](https://jenkins.brew.sh/configureSecurity/) so they can adjust settings and restart jobs - Add them to the [Jenkins' GitHub Pull Request Builder admin list](https://jenkins.brew.sh/configure) to enable `@BrewTestBot test this please` for them - Invite them to the [`homebrew-maintainers` private maintainers mailing list](https://lists.sfconservancy.org/mailman/admin/homebrew-maintainers/members/add) -- Invite them to the [`machomebrew` private maintainers Slack](https://machomebrew.slack.com/admin/invites) +- Invite them to the [`machomebrew` private maintainers Slack](https://machomebrew.slack.com/admin/invites) (and ensure they've read the [communication guidelines](Maintainer-Guidelines.md#communication)) - Invite them to the [`homebrew` private maintainers 1Password](https://homebrew.1password.com/signin) - Invite them to [Google Analytics](https://analytics.google.com/analytics/web/?authuser=1#management/Settings/a76679469w115400090p120682403/%3Fm.page%3DAccountUsers/) diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md index 8b1bd73127..9ef0843a1c 100644 --- a/docs/Troubleshooting.md +++ b/docs/Troubleshooting.md @@ -17,7 +17,7 @@ Follow these steps to fix common problems: ## Check to see if the issue has been reported * Search the [issue tracker](https://github.com/Homebrew/homebrew-core/issues) to see if someone else has already reported the same issue. -* Make sure you search issues on the correct repository. If a formula that has failed to build is part of a tap like [homebrew/php](https://github.com/Homebrew/homebrew-php/issues) or a cask is part of [caskroom/cask](https://github.com/caskroom/homebrew-cask/issues) check those issue trackers instead. +* Make sure you search issues on the correct repository. If a formula that has failed to build is part of a non-homebrew-core tap or a cask is part of [caskroom/cask](https://github.com/caskroom/homebrew-cask/issues) check those issue trackers instead. ## Create an issue diff --git a/manpages/brew-cask.1 b/manpages/brew-cask.1 index 6b32a90518..346c45d6a8 100644 --- a/manpages/brew-cask.1 +++ b/manpages/brew-cask.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BREW\-CASK" "1" "March 2018" "Homebrew" "brew-cask" +.TH "BREW\-CASK" "1" "April 2018" "Homebrew" "brew-cask" . .SH "NAME" \fBbrew\-cask\fR \- a friendly binary installer for macOS diff --git a/manpages/brew.1 b/manpages/brew.1 index ca8c6f5f14..9d2811a6a3 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BREW" "1" "March 2018" "Homebrew" "brew" +.TH "BREW" "1" "April 2018" "Homebrew" "brew" . .SH "NAME" \fBbrew\fR \- The missing package manager for macOS @@ -346,6 +346,9 @@ Check the given \fIformulae\fR for missing dependencies\. If no \fIformulae\fR a .IP If \fB\-\-hide=\fR\fIhidden\fR is passed, act as if none of \fIhidden\fR are installed\. \fIhidden\fR should be a comma\-separated list of formulae\. . +.IP +\fBmissing\fR exits with a non\-zero status if any formulae are missing dependencies\. +. .TP \fBoptions\fR [\fB\-\-compact\fR] (\fB\-\-all\fR|\fB\-\-installed\fR|\fIformulae\fR) Display install options specific to \fIformulae\fR\. @@ -388,7 +391,7 @@ Rerun the post\-install steps for \fIformula\fR\. . .TP \fBprune\fR [\fB\-\-dry\-run\fR] -Remove dead symlinks from the Homebrew prefix\. This is generally not needed, but can be useful when doing DIY installations\. Also remove broken app symlinks from \fB/Applications\fR and \fB~/Applications\fR that were previously created by \fBbrew linkapps\fR\. +Remove dead symlinks from the Homebrew prefix\. This is generally not needed, but can be useful when doing DIY installations\. . .IP If \fB\-\-dry\-run\fR or \fB\-n\fR is passed, show what would be removed, but do not actually remove anything\. @@ -455,15 +458,15 @@ Passing \fB\-\-only\-cops=\fR\fIcops\fR will check for violations of only the li Exits with a non\-zero status if any style violations are found\. . .TP -\fBswitch\fR \fIname\fR \fIversion\fR -Symlink all of the specific \fIversion\fR of \fIname\fR\'s install to Homebrew prefix\. +\fBswitch\fR \fIformula\fR \fIversion\fR +Symlink all of the specific \fIversion\fR of \fIformula\fR\'s install to Homebrew prefix\. . .TP \fBtap\fR List all installed taps\. . .TP -\fBtap\fR [\fB\-\-full\fR] \fIuser\fR\fB/\fR\fIrepo\fR [\fIURL\fR] +\fBtap\fR [\fB\-\-full\fR] [\fB\-\-force\-auto\-update\fR] \fIuser\fR\fB/\fR\fIrepo\fR [\fIURL\fR] Tap a formula repository\. . .IP @@ -476,6 +479,9 @@ With \fIURL\fR specified, taps a formula repository from anywhere, using any tra By default, the repository is cloned as a shallow copy (\fB\-\-depth=1\fR), but if \fB\-\-full\fR is passed, a full clone will be used\. To convert a shallow copy to a full copy, you can retap passing \fB\-\-full\fR without first untapping\. . .IP +By default, only taps hosted on GitHub are auto\-updated (for performance reasons)\. If \fB\-\-force\-auto\-update\fR is passed, this tap will be auto\-updated even if it is not hosted on GitHub\. +. +.IP \fBtap\fR is re\-runnable and exits successfully if there\'s nothing to do\. However, retapping with a different \fIURL\fR will cause an exception, so first \fBuntap\fR if you need to modify the \fIURL\fR\. . .TP @@ -483,10 +489,6 @@ By default, the repository is cloned as a shallow copy (\fB\-\-depth=1\fR), but Migrate tapped formulae from symlink\-based to directory\-based structure\. . .TP -\fBtap\fR \fB\-\-list\-official\fR -List all official taps\. -. -.TP \fBtap\fR \fB\-\-list\-pinned\fR List all pinned taps\. . @@ -686,7 +688,7 @@ Passing \fB\-\-only\-cops=\fR\fIcops\fR will check for violations of only the li \fBaudit\fR exits with a non\-zero status if any errors are found\. This is useful, for instance, for implementing pre\-commit hooks\. . .TP -\fBbottle\fR [\fB\-\-verbose\fR] [\fB\-\-no\-rebuild\fR|\fB\-\-keep\-old\fR] [\fB\-\-skip\-relocation\fR] [\fB\-\-root\-url=\fR\fIURL\fR] [\fB\-\-force\-core\-tap\fR] \fIformulae\fR +\fBbottle\fR [\fB\-\-verbose\fR] [\fB\-\-no\-rebuild\fR|\fB\-\-keep\-old\fR] [\fB\-\-skip\-relocation\fR] [\fB\-\-or\-later\fR] [\fB\-\-root\-url=\fR\fIURL\fR] [\fB\-\-force\-core\-tap\fR] \fIformulae\fR Generate a bottle (binary package) from a formula installed with \fB\-\-build\-bottle\fR\. . .IP @@ -702,6 +704,9 @@ If \fB\-\-skip\-relocation\fR is passed, do not check if the bottle can be marke If \fB\-\-root\-url\fR is passed, use the specified \fIURL\fR as the root of the bottle\'s URL instead of Homebrew\'s default\. . .IP +If \fB\-\-or\-later\fR is passed, append _or_later to the bottle tag\. +. +.IP If \fB\-\-force\-core\-tap\fR is passed, build a bottle even if \fIformula\fR is not in homebrew/core or any installed taps\. . .TP @@ -869,7 +874,7 @@ If \fB\-\-test\-bot\-user=\fR\fItest\-bot\-user\fR is passed, pull the bottle bl . .TP \fBrelease\-notes\fR [\fB\-\-markdown\fR] [\fIprevious_tag\fR] [\fIend_ref\fR] -Output the merged pull requests on Homebrew/brew between two Git refs\. If no \fIprevious_tag\fR is provided it defaults to the newest tag\. If no \fIend_ref\fR is provided it defaults to \fBorigin/master\fR\. +Output the merged pull requests on Homebrew/brew between two Git refs\. If no \fIprevious_tag\fR is provided it defaults to the latest tag\. If no \fIend_ref\fR is provided it defaults to \fBorigin/master\fR\. . .IP If \fB\-\-markdown\fR is passed, output as a Markdown list\. @@ -1096,6 +1101,7 @@ An arbitrary URL Homebrew can install formulae via URL, e\.g\. \fBhttps://raw\.github\.com/Homebrew/homebrew\-core/master/Formula/git\.rb\fR\. The formula file will be cached for later use\. . .SH "ENVIRONMENT" +Note that environment variables must have a value set to be detected\. For example, \fBexport HOMEBREW_NO_INSECURE_REDIRECT=1\fR rather than just \fBexport HOMEBREW_NO_INSECURE_REDIRECT\fR\. . .TP \fBHOMEBREW_ARTIFACT_DOMAIN\fR @@ -1132,6 +1138,10 @@ If set, instructs Homebrew to use the given directory as the download cache\. \fIDefault:\fR \fB~/Library/Caches/Homebrew\fR\. . .TP +\fBHOMEBREW_CURLRC\fR +If set, Homebrew will not pass \fB\-q\fR when invoking \fBcurl\fR(1) (which disables the use of \fBcurlrc\fR)\. +. +.TP \fBHOMEBREW_CURL_VERBOSE\fR If set, Homebrew will pass \fB\-\-verbose\fR when invoking \fBcurl\fR(1)\. .