From e9b9ea49a16b7879731d01ff2842460d33257a06 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 17 Sep 2018 02:45:00 +0200 Subject: [PATCH] Update to RuboCop 0.59.1. --- Library/.rubocop.yml | 5 ++- Library/Homebrew/.rubocop.yml | 5 +++ Library/Homebrew/brew.rb | 1 + Library/Homebrew/build.rb | 1 + Library/Homebrew/cache_store.rb | 2 + .../cask/artifact/abstract_flight_block.rb | 1 + .../cask/artifact/abstract_uninstall.rb | 8 ++++ Library/Homebrew/cask/artifact/binary.rb | 1 + Library/Homebrew/cask/artifact/moved.rb | 3 ++ Library/Homebrew/cask/artifact/pkg.rb | 1 + Library/Homebrew/cask/artifact/relocated.rb | 2 + Library/Homebrew/cask/artifact/symlinked.rb | 1 + Library/Homebrew/cask/audit.rb | 17 ++++++++ Library/Homebrew/cask/cask.rb | 3 ++ Library/Homebrew/cask/cask_dependencies.rb | 2 + Library/Homebrew/cask/cask_loader.rb | 1 + Library/Homebrew/cask/cmd.rb | 1 + Library/Homebrew/cask/cmd/abstract_command.rb | 1 + Library/Homebrew/cask/cmd/audit.rb | 1 + Library/Homebrew/cask/cmd/doctor.rb | 3 ++ Library/Homebrew/cask/cmd/edit.rb | 1 + Library/Homebrew/cask/cmd/info.rb | 1 + Library/Homebrew/cask/cmd/internal_help.rb | 2 + Library/Homebrew/cask/cmd/internal_stanza.rb | 1 + Library/Homebrew/cask/cmd/list.rb | 1 + Library/Homebrew/cask/cmd/options.rb | 3 ++ Library/Homebrew/cask/cmd/upgrade.rb | 1 + Library/Homebrew/cask/dsl.rb | 5 +++ Library/Homebrew/cask/dsl/caveats.rb | 3 ++ Library/Homebrew/cask/dsl/conflicts_with.rb | 1 + Library/Homebrew/cask/dsl/container.rb | 2 + Library/Homebrew/cask/dsl/depends_on.rb | 5 +++ Library/Homebrew/cask/dsl/version.rb | 1 + Library/Homebrew/cask/installer.rb | 11 +++++ Library/Homebrew/cask/pkg.rb | 2 + Library/Homebrew/cask/staged.rb | 2 + Library/Homebrew/cask/url.rb | 1 + Library/Homebrew/cleanup.rb | 3 ++ Library/Homebrew/cli_parser.rb | 3 ++ Library/Homebrew/cmd/analytics.rb | 1 + Library/Homebrew/cmd/commands.rb | 2 + Library/Homebrew/cmd/deps.rb | 3 ++ Library/Homebrew/cmd/desc.rb | 1 + Library/Homebrew/cmd/doctor.rb | 1 + Library/Homebrew/cmd/fetch.rb | 2 + Library/Homebrew/cmd/gist-logs.rb | 1 + Library/Homebrew/cmd/info.rb | 2 + Library/Homebrew/cmd/install.rb | 4 ++ Library/Homebrew/cmd/list.rb | 3 ++ Library/Homebrew/cmd/options.rb | 2 + Library/Homebrew/cmd/prune.rb | 1 + Library/Homebrew/cmd/search.rb | 2 + Library/Homebrew/cmd/tap-pin.rb | 1 + Library/Homebrew/cmd/tap-unpin.rb | 1 + Library/Homebrew/cmd/uninstall.rb | 1 + Library/Homebrew/cmd/unpack.rb | 2 + Library/Homebrew/cmd/untap.rb | 1 + Library/Homebrew/cmd/update-report.rb | 9 +++++ Library/Homebrew/cmd/upgrade.rb | 1 + Library/Homebrew/cmd/uses.rb | 1 + Library/Homebrew/compat/cask/cmd/--version.rb | 1 + Library/Homebrew/constants.rb | 4 +- Library/Homebrew/cxxstdlib.rb | 1 + Library/Homebrew/dependable.rb | 2 + Library/Homebrew/dependencies.rb | 2 + Library/Homebrew/dependency.rb | 3 ++ Library/Homebrew/dependency_collector.rb | 2 + Library/Homebrew/descriptions.rb | 3 ++ Library/Homebrew/dev-cmd/audit.rb | 23 +++++++++++ Library/Homebrew/dev-cmd/bottle.rb | 8 ++++ Library/Homebrew/dev-cmd/bump-formula-pr.rb | 4 ++ Library/Homebrew/dev-cmd/create.rb | 1 + Library/Homebrew/dev-cmd/edit.rb | 1 + Library/Homebrew/dev-cmd/extract.rb | 3 ++ Library/Homebrew/dev-cmd/formula.rb | 1 + Library/Homebrew/dev-cmd/pull.rb | 13 ++++++ Library/Homebrew/dev-cmd/release-notes.rb | 1 + Library/Homebrew/dev-cmd/tap-new.rb | 1 + Library/Homebrew/dev-cmd/test.rb | 1 + Library/Homebrew/dev-cmd/tests.rb | 1 + Library/Homebrew/diagnostic.rb | 11 +++++ Library/Homebrew/download_strategy.rb | 13 ++++++ Library/Homebrew/exceptions.rb | 1 + Library/Homebrew/extend/ARGV.rb | 3 ++ Library/Homebrew/extend/ENV.rb | 1 + Library/Homebrew/extend/ENV/shared.rb | 7 ++++ Library/Homebrew/extend/ENV/std.rb | 2 + Library/Homebrew/extend/ENV/super.rb | 1 + Library/Homebrew/extend/git_repository.rb | 7 ++++ Library/Homebrew/extend/hash_validator.rb | 1 + Library/Homebrew/extend/io.rb | 2 + .../Homebrew/extend/os/linux/diagnostic.rb | 3 ++ .../extend/os/linux/extend/ENV/super.rb | 1 + .../Homebrew/extend/os/linux/hardware/cpu.rb | 1 + .../Homebrew/extend/os/linux/keg_relocate.rb | 3 ++ .../linux/requirements/osxfuse_requirement.rb | 2 + .../Homebrew/extend/os/linux/system_config.rb | 3 ++ .../extend/os/mac/dependency_collector.rb | 4 ++ Library/Homebrew/extend/os/mac/diagnostic.rb | 1 + .../Homebrew/extend/os/mac/extend/ENV/std.rb | 3 ++ .../extend/os/mac/extend/ENV/super.rb | 1 + .../extend/os/mac/formula_cellar_checks.rb | 2 + .../Homebrew/extend/os/mac/keg_relocate.rb | 3 ++ .../os/mac/requirements/java_requirement.rb | 2 + .../os/mac/requirements/x11_requirement.rb | 1 + .../Homebrew/extend/os/mac/system_config.rb | 1 + .../Homebrew/extend/os/mac/utils/bottles.rb | 2 + Library/Homebrew/extend/pathname.rb | 8 ++++ Library/Homebrew/extend/string.rb | 1 + Library/Homebrew/fetch.rb | 1 + Library/Homebrew/formula.rb | 28 +++++++++++++ Library/Homebrew/formula_cellar_checks.rb | 5 +++ Library/Homebrew/formula_creator.rb | 1 + Library/Homebrew/formula_installer.rb | 16 ++++++++ Library/Homebrew/formula_support.rb | 1 + Library/Homebrew/formula_versions.rb | 2 + Library/Homebrew/formulary.rb | 2 + Library/Homebrew/hardware.rb | 1 + Library/Homebrew/install.rb | 1 + Library/Homebrew/keg.rb | 17 ++++++++ Library/Homebrew/keg_relocate.rb | 8 ++++ Library/Homebrew/language/node.rb | 2 + Library/Homebrew/language/python.rb | 9 +++++ Library/Homebrew/lazy_object.rb | 1 + Library/Homebrew/linkage_cache_store.rb | 1 + Library/Homebrew/linkage_checker.rb | 9 +++++ Library/Homebrew/locale.rb | 1 + Library/Homebrew/lock_file.rb | 3 ++ Library/Homebrew/messages.rb | 2 + Library/Homebrew/metafiles.rb | 1 + Library/Homebrew/migrator.rb | 9 +++++ Library/Homebrew/missing_formula.rb | 2 + Library/Homebrew/options.rb | 1 + Library/Homebrew/os.rb | 2 + Library/Homebrew/os/linux/elf.rb | 3 ++ Library/Homebrew/os/linux/glibc.rb | 2 + Library/Homebrew/os/mac/keg.rb | 2 + Library/Homebrew/os/mac/mach.rb | 1 + Library/Homebrew/os/mac/sdk.rb | 1 + Library/Homebrew/os/mac/xcode.rb | 9 +++++ Library/Homebrew/os/mac/xquartz.rb | 1 + Library/Homebrew/patch.rb | 1 + Library/Homebrew/pkg_version.rb | 1 + Library/Homebrew/requirement.rb | 7 ++++ .../Homebrew/requirements/java_requirement.rb | 6 +++ .../requirements/macos_requirement.rb | 3 ++ .../Homebrew/requirements/x11_requirement.rb | 1 + .../requirements/xcode_requirement.rb | 1 + Library/Homebrew/resource.rb | 3 ++ Library/Homebrew/rubocops/caveats_cop.rb | 1 + Library/Homebrew/rubocops/checksum_cop.rb | 5 +++ Library/Homebrew/rubocops/class_cop.rb | 2 + .../Homebrew/rubocops/components_order_cop.rb | 3 ++ .../rubocops/components_redundancy_cop.rb | 1 + Library/Homebrew/rubocops/conflicts_cop.rb | 1 + .../Homebrew/rubocops/dependency_order_cop.rb | 5 +++ .../Homebrew/rubocops/extend/formula_cop.rb | 40 +++++++++++++++++-- Library/Homebrew/rubocops/formula_desc_cop.rb | 2 + Library/Homebrew/rubocops/lines_cop.rb | 35 ++++++++++++++++ Library/Homebrew/rubocops/options_cop.rb | 2 + Library/Homebrew/rubocops/patches_cop.rb | 2 + Library/Homebrew/rubocops/text_cop.rb | 2 + Library/Homebrew/rubocops/urls_cop.rb | 3 ++ Library/Homebrew/sandbox.rb | 3 ++ Library/Homebrew/software_spec.rb | 6 +++ Library/Homebrew/style.rb | 2 + Library/Homebrew/system_command.rb | 3 ++ Library/Homebrew/system_config.rb | 6 +++ Library/Homebrew/tab.rb | 2 + Library/Homebrew/tap.rb | 20 ++++++++++ Library/Homebrew/test/Gemfile.lock | 4 +- .../helper/cask/fake_system_command.rb | 1 + .../Homebrew/test/support/helper/mktmpdir.rb | 1 + .../test/support/helper/output_as_tty.rb | 2 + .../spec/shared_context/integration_test.rb | 1 + Library/Homebrew/unpack_strategy/dmg.rb | 1 + Library/Homebrew/update_migrator.rb | 2 + Library/Homebrew/utils.rb | 10 +++++ Library/Homebrew/utils/analytics.rb | 3 ++ Library/Homebrew/utils/bottles.rb | 3 ++ Library/Homebrew/utils/curl.rb | 3 ++ Library/Homebrew/utils/git.rb | 3 ++ Library/Homebrew/utils/github.rb | 4 ++ Library/Homebrew/utils/link.rb | 6 +++ Library/Homebrew/utils/popen.rb | 3 ++ Library/Homebrew/utils/shell.rb | 2 + Library/Homebrew/utils/svn.rb | 2 + Library/Homebrew/utils/tty.rb | 2 + Library/Homebrew/version.rb | 3 ++ 189 files changed, 680 insertions(+), 8 deletions(-) diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index 8606d8974f..4159a6eb29 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -47,11 +47,14 @@ Layout/SpaceAroundOperators: Layout/Tab: Enabled: true +# Auto-correct is broken (https://github.com/rubocop-hq/rubocop/issues/6300). +Layout/EmptyLineAfterGuardClause: + Enabled: false + # favour parens-less DSL-style arguments Lint/AmbiguousBlockAssociation: Enabled: false - # so many of these in formulae and can't be autocorrected # TODO: fix these as `ruby -w` complains about them. Lint/AmbiguousRegexpLiteral: diff --git a/Library/Homebrew/.rubocop.yml b/Library/Homebrew/.rubocop.yml index da003e380b..daf631a039 100644 --- a/Library/Homebrew/.rubocop.yml +++ b/Library/Homebrew/.rubocop.yml @@ -97,6 +97,11 @@ Naming/UncommunicativeMethodParamName: - 'to' - 'v' +# Auto-correct is broken (https://github.com/rubocop-hq/rubocop/issues/6258) +# and layout is not configurable (https://github.com/rubocop-hq/rubocop/issues/6254). +Layout/RescueEnsureAlignment: + Enabled: false + # Avoid false positives on modifiers used on symbols of methods # See https://github.com/rubocop-hq/rubocop/issues/5953 Style/AccessModifierDeclarations: diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index 162fae41e1..161862289a 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -128,6 +128,7 @@ rescue BuildError => e exit 1 rescue RuntimeError, SystemCallError => e raise if e.message.empty? + onoe e $stderr.puts e.backtrace if ARGV.debug? exit 1 diff --git a/Library/Homebrew/build.rb b/Library/Homebrew/build.rb index 3d72481687..df2565da66 100644 --- a/Library/Homebrew/build.rb +++ b/Library/Homebrew/build.rb @@ -32,6 +32,7 @@ class Build # Only allow Homebrew-approved directories into the PATH, unless # a formula opts-in to allowing the user's path. return unless formula.env.userpaths? || reqs.any? { |rq| rq.env.userpaths? } + ENV.userpaths! end diff --git a/Library/Homebrew/cache_store.rb b/Library/Homebrew/cache_store.rb index c86a4b8044..80232dd897 100644 --- a/Library/Homebrew/cache_store.rb +++ b/Library/Homebrew/cache_store.rb @@ -26,12 +26,14 @@ class CacheStoreDatabase # Gets a value from the underlying database (if it already exists). def get(key) return unless created? + db[key] end # Gets a value from the underlying database (if it already exists). def delete(key) return unless created? + db.delete(key) end diff --git a/Library/Homebrew/cask/artifact/abstract_flight_block.rb b/Library/Homebrew/cask/artifact/abstract_flight_block.rb index 3da3ba391d..dff490b77a 100644 --- a/Library/Homebrew/cask/artifact/abstract_flight_block.rb +++ b/Library/Homebrew/cask/artifact/abstract_flight_block.rb @@ -35,6 +35,7 @@ module Cask def abstract_phase(dsl_key) return if (block = directives[dsl_key]).nil? + class_for_dsl_key(dsl_key).new(cask).instance_eval(&block) end diff --git a/Library/Homebrew/cask/artifact/abstract_uninstall.rb b/Library/Homebrew/cask/artifact/abstract_uninstall.rb index cabf5306fb..679c459ec9 100644 --- a/Library/Homebrew/cask/artifact/abstract_uninstall.rb +++ b/Library/Homebrew/cask/artifact/abstract_uninstall.rb @@ -54,6 +54,7 @@ module Cask ORDERED_DIRECTIVES.each do |directive_sym| next unless directives.key?(directive_sym) + args = directives[directive_sym] send("uninstall_#{directive_sym}", *(args.is_a?(Hash) ? [args] : args), **options) end @@ -66,6 +67,7 @@ module Cask def warn_for_unknown_directives(directives) unknown_keys = directives.keys - ORDERED_DIRECTIVES return if unknown_keys.empty? + opoo "Unknown arguments to #{stanza} -- #{unknown_keys.inspect}. " \ "Running \"brew update; brew cleanup\" will likely fix it." end @@ -100,6 +102,7 @@ module Cask end # undocumented and untested: pass a path to uninstall :launchctl next unless Pathname(service).exist? + command.run!("/bin/launchctl", args: ["unload", "-w", "--", service], sudo: with_sudo) command.run!("/bin/rm", args: ["-f", "--", service], sudo: with_sudo) sleep 1 @@ -113,6 +116,7 @@ module Cask .map { |pid, state, id| [pid.to_i, state.to_i, id] } .select do |fields| next if fields[0].zero? + fields[2] =~ /^#{Regexp.escape(bundle_id)}($|\.\d+)/ end end @@ -122,6 +126,7 @@ module Cask bundle_ids.each do |bundle_id| ohai "Quitting application ID #{bundle_id}" next if running_processes(bundle_id, command: command).empty? + command.run!("/usr/bin/osascript", args: ["-e", %Q(tell application id "#{bundle_id}" to quit)], sudo: true) begin @@ -147,6 +152,7 @@ module Cask ohai "Signalling '#{signal}' to application ID '#{bundle_id}'" pids = running_processes(bundle_id, command: command).map(&:first) next unless pids.any? + # Note that unlike :quit, signals are sent from the current user (not # upgraded to the superuser). This is a todo item for the future, but # there should be some additional thought/safety checks about that, as a @@ -201,11 +207,13 @@ module Cask ohai "Running uninstall script #{executable}" raise CaskInvalidError.new(cask, "#{stanza} :#{directive_name} without :executable.") if executable.nil? + executable_path = cask.staged_path.join(executable) unless executable_path.exist? message = "uninstall script #{executable} does not exist" raise CaskError, "#{message}." unless force + opoo "#{message}, skipping." return end diff --git a/Library/Homebrew/cask/artifact/binary.rb b/Library/Homebrew/cask/artifact/binary.rb index 353b094e45..a630e7c6fd 100644 --- a/Library/Homebrew/cask/artifact/binary.rb +++ b/Library/Homebrew/cask/artifact/binary.rb @@ -6,6 +6,7 @@ module Cask def link(command: nil, **options) super(command: command, **options) return if source.executable? + if source.writable? FileUtils.chmod "+x", source else diff --git a/Library/Homebrew/cask/artifact/moved.rb b/Library/Homebrew/cask/artifact/moved.rb index 7840e95c4b..eb97424f9a 100644 --- a/Library/Homebrew/cask/artifact/moved.rb +++ b/Library/Homebrew/cask/artifact/moved.rb @@ -30,6 +30,7 @@ module Cask message = "It seems there is already #{self.class.english_article} " \ "#{self.class.english_name} at '#{target}'" raise CaskError, "#{message}." unless force + opoo "#{message}; overwriting." delete(target, force: force, command: command, **options) end @@ -55,12 +56,14 @@ module Cask message = "It seems there is already #{self.class.english_article} " \ "#{self.class.english_name} at '#{source}'" raise CaskError, "#{message}." unless force + opoo "#{message}; overwriting." delete(source, force: force, command: command, **options) end unless target.exist? return if skip || force + raise CaskError, "It seems the #{self.class.english_name} source '#{target}' is not there." end diff --git a/Library/Homebrew/cask/artifact/pkg.rb b/Library/Homebrew/cask/artifact/pkg.rb index bade72ab9f..56b10d7bbe 100644 --- a/Library/Homebrew/cask/artifact/pkg.rb +++ b/Library/Homebrew/cask/artifact/pkg.rb @@ -39,6 +39,7 @@ module Cask unless path.exist? raise CaskError, "pkg source file not found: '#{path.relative_path_from(cask.staged_path)}'" end + args = [ "-pkg", path, "-target", "/" diff --git a/Library/Homebrew/cask/artifact/relocated.rb b/Library/Homebrew/cask/artifact/relocated.rb index 81006cd533..85ae8fa9d9 100644 --- a/Library/Homebrew/cask/artifact/relocated.rb +++ b/Library/Homebrew/cask/artifact/relocated.rb @@ -11,6 +11,7 @@ module Cask if target_hash raise CaskInvalidError unless target_hash.respond_to?(:keys) + target_hash.assert_valid_keys!(:target) end @@ -56,6 +57,7 @@ module Cask # bundles. Alfred 2.2 respects it even for App bundles. def add_altname_metadata(file, altname, command: nil) return if altname.to_s.casecmp(file.basename.to_s).zero? + odebug "Adding #{ALT_NAME_ATTRIBUTE} metadata" altnames = command.run("/usr/bin/xattr", args: ["-p", ALT_NAME_ATTRIBUTE, file], diff --git a/Library/Homebrew/cask/artifact/symlinked.rb b/Library/Homebrew/cask/artifact/symlinked.rb index 281a8e6e2c..dc6d434e2c 100644 --- a/Library/Homebrew/cask/artifact/symlinked.rb +++ b/Library/Homebrew/cask/artifact/symlinked.rb @@ -54,6 +54,7 @@ module Cask def unlink(**) return unless target.symlink? + ohai "Unlinking #{self.class.english_name} '#{target}'." target.delete end diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 5d71375dda..8a5d0b53db 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -65,6 +65,7 @@ module Cask return if tap.user != "Homebrew" return unless cask.artifacts.any? { |k| k.is_a?(Artifact::Pkg) && k.stanza_options.key?(:allow_untrusted) } + add_warning "allow_untrusted is not permitted in official Homebrew Cask taps" end @@ -73,6 +74,7 @@ module Cask return if cask.artifacts.none? { |k| k.is_a?(Artifact::Pkg) || k.is_a?(Artifact::Installer) } return if cask.artifacts.any? { |k| k.is_a?(Artifact::Uninstall) } + add_warning "installer and pkg stanzas require an uninstall stanza" end @@ -118,6 +120,7 @@ module Cask end return unless cask.artifacts.count { |k| k.is_a?(Artifact::Zap) } > 1 + add_warning "only a single zap stanza is allowed" end @@ -141,6 +144,7 @@ module Cask return if tap.nil? return if commit_range.nil? + previous_cask_contents = Git.last_revision_of_file(tap.path, @cask.sourcefile_path, before_commit: commit_range) return if previous_cask_contents.empty? @@ -158,6 +162,7 @@ module Cask def check_version return unless cask.version + check_no_string_version_latest check_no_file_separator_in_version end @@ -165,6 +170,7 @@ module Cask def check_no_string_version_latest odebug "Verifying version :latest does not appear as a string ('latest')" return unless cask.version.raw_version == "latest" + add_error "you should use version :latest instead of version 'latest'" end @@ -172,11 +178,13 @@ module Cask odebug "Verifying version does not contain '#{File::SEPARATOR}'" return unless cask.version.raw_version.is_a?(String) return unless cask.version.raw_version.include?(File::SEPARATOR) + add_error "version should not contain '#{File::SEPARATOR}'" end def check_sha256 return unless cask.sha256 + check_sha256_no_check_if_latest check_sha256_actually_256 check_sha256_invalid @@ -186,6 +194,7 @@ module Cask odebug "Verifying sha256 :no_check with version :latest" return unless cask.version.latest? return if cask.sha256 == :no_check + add_error "you should use sha256 :no_check when version is :latest" end @@ -193,6 +202,7 @@ module Cask odebug "Verifying #{stanza} string is a legal SHA-256 digest" return unless sha256.is_a?(String) return if sha256.length == 64 && sha256[/^[0-9a-f]+$/i] + add_error "#{stanza} string must be of 64 hexadecimal characters" end @@ -200,6 +210,7 @@ module Cask odebug "Verifying #{stanza} is not a known invalid value" empty_sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" return unless sha256 == empty_sha256 + add_error "cannot use the sha256 for an empty string in #{stanza}: #{empty_sha256}" end @@ -232,9 +243,11 @@ module Cask case cask.url.to_s when %r{github.com/([^/]+)/([^/]+)/releases/download/(\S+)} return if cask.version.latest? + add_warning "Download uses GitHub releases, #{add_appcast}" when %r{sourceforge.net/(\S+)} return if cask.version.latest? + add_warning "Download is hosted on SourceForge, #{add_appcast}" when %r{dl.devmate.com/(\S+)} add_warning "Download is hosted on DevMate, #{add_appcast}" @@ -245,6 +258,7 @@ module Cask def check_url return unless cask.url + check_download_url_format end @@ -259,6 +273,7 @@ module Cask def bad_url_format?(regex, valid_formats_array) return false unless cask.url.to_s =~ regex + valid_formats_array.none? { |format| cask.url.to_s =~ format } end @@ -289,6 +304,7 @@ module Cask def check_token_conflicts return unless check_token_conflicts? return unless core_formula_names.include?(cask.token) + add_warning "possible duplicate, cask token conflicts with Homebrew core formula: #{core_formula_url}" end @@ -306,6 +322,7 @@ module Cask def check_download return unless download && cask.url + odebug "Auditing download" downloaded_path = download.perform Verify.all(cask, downloaded_path) diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index cdd1a52a25..f0f5e3b392 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -27,6 +27,7 @@ module Cask def tap return super if block_given? # Object#tap + @tap end @@ -37,6 +38,7 @@ module Cask @config = config @dsl = DSL.new(self) return unless block_given? + @dsl.instance_eval(&block) @dsl.language_eval end @@ -62,6 +64,7 @@ module Cask def full_name return token if tap.nil? return token if tap.user == "Homebrew" + "#{tap.name}/#{token}" end diff --git a/Library/Homebrew/cask/cask_dependencies.rb b/Library/Homebrew/cask/cask_dependencies.rb index 3839ca6670..bd8a822760 100644 --- a/Library/Homebrew/cask/cask_dependencies.rb +++ b/Library/Homebrew/cask/cask_dependencies.rb @@ -16,6 +16,7 @@ module Cask def graph_dependencies(cask = self.cask, acc = TopologicalHash.new) return acc if acc.key?(cask) + deps = cask.depends_on.cask.map(&CaskLoader.public_method(:load)) acc[cask] = deps deps.each do |dep| @@ -26,6 +27,7 @@ module Cask def sort raise CaskSelfReferencingDependencyError, cask.token if graph[cask].include?(cask) + graph.tsort - [cask] rescue TSort::Cyclic strongly_connected_components = graph.strongly_connected_components.sort_by(&:count) diff --git a/Library/Homebrew/cask/cask_loader.rb b/Library/Homebrew/cask/cask_loader.rb index 68f78e4bd9..70ccf15d25 100644 --- a/Library/Homebrew/cask/cask_loader.rb +++ b/Library/Homebrew/cask/cask_loader.rb @@ -8,6 +8,7 @@ module Cask def self.can_load?(ref) return false unless ref.respond_to?(:to_str) + content = ref.to_str token = /(?:"[^"]*"|'[^']*')/ diff --git a/Library/Homebrew/cask/cmd.rb b/Library/Homebrew/cask/cmd.rb index 4e5ee13b2f..a064a30333 100644 --- a/Library/Homebrew/cask/cmd.rb +++ b/Library/Homebrew/cask/cmd.rb @@ -236,6 +236,7 @@ module Cask puts "Commands:\n\n" Cmd.command_classes.each do |klass| next unless klass.visible + puts " #{klass.command_name.ljust(max_command_len)} #{_help_for(klass)}" end puts %Q(\nSee also "man brew-cask") diff --git a/Library/Homebrew/cask/cmd/abstract_command.rb b/Library/Homebrew/cask/cmd/abstract_command.rb index 07f118e30f..9b6510269f 100644 --- a/Library/Homebrew/cask/cmd/abstract_command.rb +++ b/Library/Homebrew/cask/cmd/abstract_command.rb @@ -45,6 +45,7 @@ module Cask def casks(alternative: -> { [] }) return @casks if defined?(@casks) + casks = args.empty? ? alternative.call : args @casks = casks.map { |cask| CaskLoader.load(cask) } rescue CaskUnavailableError => e diff --git a/Library/Homebrew/cask/cmd/audit.rb b/Library/Homebrew/cask/cmd/audit.rb index 02f41de920..7bfff0d2f0 100644 --- a/Library/Homebrew/cask/cmd/audit.rb +++ b/Library/Homebrew/cask/cmd/audit.rb @@ -13,6 +13,7 @@ module Cask .reject { |cask| audit(cask) } return if failed_casks.empty? + raise CaskError, "audit failed for casks: #{failed_casks.join(" ")}" end diff --git a/Library/Homebrew/cask/cmd/doctor.rb b/Library/Homebrew/cask/cmd/doctor.rb index 2fd07ee071..7c3095d8df 100644 --- a/Library/Homebrew/cask/cmd/doctor.rb +++ b/Library/Homebrew/cask/cmd/doctor.rb @@ -9,6 +9,7 @@ module Cask def initialize(*) super return if args.empty? + raise ArgumentError, "#{self.class.command_name} does not take arguments." end @@ -151,6 +152,7 @@ module Cask def self.check_sip csrutil = "/usr/bin/csrutil" return "N/A" unless File.executable?(csrutil) + Open3.capture2(csrutil, "status") .first .gsub("This is an unsupported configuration, likely to break in " \ @@ -186,6 +188,7 @@ module Cask def self.render_env_var(var) return unless ENV.key?(var) + var = %Q(#{var}="#{ENV[var]}") puts user_tilde(var) end diff --git a/Library/Homebrew/cask/cmd/edit.rb b/Library/Homebrew/cask/cmd/edit.rb index 9870185c17..bccdc27547 100644 --- a/Library/Homebrew/cask/cmd/edit.rb +++ b/Library/Homebrew/cask/cmd/edit.rb @@ -20,6 +20,7 @@ module Cask rescue CaskInvalidError path = CaskLoader.path(args.first) return path if path.file? + raise end diff --git a/Library/Homebrew/cask/cmd/info.rb b/Library/Homebrew/cask/cmd/info.rb index ff9d5c75c4..109162bec8 100644 --- a/Library/Homebrew/cask/cmd/info.rb +++ b/Library/Homebrew/cask/cmd/info.rb @@ -90,6 +90,7 @@ module Cask cask.artifacts.each do |artifact| next unless artifact.respond_to?(:install_phase) next unless DSL::ORDINARY_ARTIFACT_CLASSES.include?(artifact.class) + puts artifact.to_s end end diff --git a/Library/Homebrew/cask/cmd/internal_help.rb b/Library/Homebrew/cask/cmd/internal_help.rb index e680d46ea3..9698a405f6 100644 --- a/Library/Homebrew/cask/cmd/internal_help.rb +++ b/Library/Homebrew/cask/cmd/internal_help.rb @@ -4,6 +4,7 @@ module Cask def initialize(*) super return if args.empty? + raise ArgumentError, "#{self.class.command_name} does not take arguments." end @@ -12,6 +13,7 @@ module Cask puts "Unstable Internal-use Commands:\n\n" Cmd.command_classes.each do |klass| next if klass.visible + puts " #{klass.command_name.ljust(max_command_len)} #{self.class.help_for(klass)}" end puts "\n" diff --git a/Library/Homebrew/cask/cmd/internal_stanza.rb b/Library/Homebrew/cask/cmd/internal_stanza.rb index 97387a31e0..fe6527901a 100644 --- a/Library/Homebrew/cask/cmd/internal_stanza.rb +++ b/Library/Homebrew/cask/cmd/internal_stanza.rb @@ -45,6 +45,7 @@ module Cask @format = :to_yaml if yaml? return if DSL::DSL_METHODS.include?(stanza) + raise ArgumentError, <<~EOS Unknown/unsupported stanza: '#{stanza}' diff --git a/Library/Homebrew/cask/cmd/list.rb b/Library/Homebrew/cask/cmd/list.rb index d836f51ead..9d336366d5 100644 --- a/Library/Homebrew/cask/cmd/list.rb +++ b/Library/Homebrew/cask/cmd/list.rb @@ -32,6 +32,7 @@ module Cask def self.list_artifacts(cask) cask.artifacts.group_by(&:class).each do |klass, artifacts| next unless klass.respond_to?(:english_description) + ohai klass.english_description, artifacts.map(&:summarize_installed) end end diff --git a/Library/Homebrew/cask/cmd/options.rb b/Library/Homebrew/cask/cmd/options.rb index 9acdfbf8cd..8de1a28631 100644 --- a/Library/Homebrew/cask/cmd/options.rb +++ b/Library/Homebrew/cask/cmd/options.rb @@ -9,6 +9,7 @@ module Cask def options @options ||= {} return @options unless superclass.respond_to?(:options) + superclass.options.merge(@options) end @@ -25,11 +26,13 @@ module Cask if [true, false].include?(default_value) define_method(:"#{method}?") do return default_value unless instance_variable_defined?(:"@#{method}") + instance_variable_get(:"@#{method}") == true end else define_method(:"#{method}") do return default_value unless instance_variable_defined?(:"@#{method}") + instance_variable_get(:"@#{method}") end end diff --git a/Library/Homebrew/cask/cmd/upgrade.rb b/Library/Homebrew/cask/cmd/upgrade.rb index 8bab75d853..33d9d6380f 100644 --- a/Library/Homebrew/cask/cmd/upgrade.rb +++ b/Library/Homebrew/cask/cmd/upgrade.rb @@ -18,6 +18,7 @@ module Cask end }).select do |cask| raise CaskNotInstalledError, cask unless cask.installed? || force? + cask.outdated?(true) end diff --git a/Library/Homebrew/cask/dsl.rb b/Library/Homebrew/cask/dsl.rb index 078c722074..5cfb108abe 100644 --- a/Library/Homebrew/cask/dsl.rb +++ b/Library/Homebrew/cask/dsl.rb @@ -87,6 +87,7 @@ module Cask def name(*args) @name ||= [] return @name if args.empty? + @name.concat(args.flatten) end @@ -188,6 +189,7 @@ module Cask if !arg.is_a?(String) && arg != :latest raise CaskInvalidError.new(cask, "invalid 'version' value: '#{arg.inspect}'") end + DSL::Version.new(arg) end end @@ -197,6 +199,7 @@ module Cask if !arg.is_a?(String) && arg != :no_check raise CaskInvalidError.new(cask, "invalid 'sha256' value: '#{arg.inspect}'") end + arg end end @@ -205,6 +208,7 @@ module Cask def depends_on(*args) @depends_on ||= DSL::DependsOn.new return @depends_on if args.empty? + begin @depends_on.load(*args) rescue RuntimeError => e @@ -228,6 +232,7 @@ module Cask def staged_path return @staged_path if @staged_path + cask_version = version || :unknown @staged_path = caskroom_path.join(cask_version.to_s) end diff --git a/Library/Homebrew/cask/dsl/caveats.rb b/Library/Homebrew/cask/dsl/caveats.rb index 806a6c76d8..d2e7ac6c9a 100644 --- a/Library/Homebrew/cask/dsl/caveats.rb +++ b/Library/Homebrew/cask/dsl/caveats.rb @@ -39,11 +39,13 @@ module Cask result = instance_eval(&block) return unless result return if result == :built_in_caveat + @custom_caveats << result.to_s.sub(/\s*\Z/, "\n") end caveat :kext do next if MacOS.version < :high_sierra + <<~EOS To install and/or use #{@cask} you may need to enable their kernel extension in @@ -76,6 +78,7 @@ module Cask caveat :files_in_usr_local do next unless HOMEBREW_PREFIX.to_s.downcase.start_with?("/usr/local") + <<~EOS Cask #{@cask} installs files under /usr/local. The presence of such files can cause warnings when running "brew doctor", which is considered diff --git a/Library/Homebrew/cask/dsl/conflicts_with.rb b/Library/Homebrew/cask/dsl/conflicts_with.rb index 10cd3f0728..fa05f584c1 100644 --- a/Library/Homebrew/cask/dsl/conflicts_with.rb +++ b/Library/Homebrew/cask/dsl/conflicts_with.rb @@ -21,6 +21,7 @@ module Cask pairs.each do |key, value| raise "invalid conflicts_with key: '#{key.inspect}'" unless VALID_KEYS.include?(key) + instance_variable_set("@#{key}", instance_variable_get("@#{key}").merge([*value])) end end diff --git a/Library/Homebrew/cask/dsl/container.rb b/Library/Homebrew/cask/dsl/container.rb index 5aa1619d15..9e5e678c4d 100644 --- a/Library/Homebrew/cask/dsl/container.rb +++ b/Library/Homebrew/cask/dsl/container.rb @@ -15,11 +15,13 @@ module Cask @pairs = pairs pairs.each do |key, value| raise "invalid container key: '#{key.inspect}'" unless VALID_KEYS.include?(key) + send(:"#{key}=", value) end return if type.nil? return unless UnpackStrategy.from_type(type).nil? + raise "invalid container type: #{type.inspect}" end diff --git a/Library/Homebrew/cask/dsl/depends_on.rb b/Library/Homebrew/cask/dsl/depends_on.rb index 51f31f5736..519b0a5c67 100644 --- a/Library/Homebrew/cask/dsl/depends_on.rb +++ b/Library/Homebrew/cask/dsl/depends_on.rb @@ -30,6 +30,7 @@ module Cask def load(**pairs) pairs.each do |key, value| raise "invalid depends_on key: '#{key.inspect}'" unless VALID_KEYS.include?(key) + self[key] = send(:"#{key}=", *value) end end @@ -65,11 +66,13 @@ module Cask @macos ||= [] macos = if args.count == 1 && args.first =~ /^\s*(<|>|[=<>]=)\s*(\S+)\s*$/ raise "'depends_on macos' comparison expressions cannot be combined" unless @macos.empty? + operator = Regexp.last_match[1].to_sym release = self.class.coerce_os_release(Regexp.last_match[2]) [[operator, release]] else raise "'depends_on macos' comparison expressions cannot be combined" if @macos.first.is_a?(Symbol) + args.map(&self.class.method(:coerce_os_release)).sort end @macos.concat(macos) @@ -82,11 +85,13 @@ module Cask end invalid_arches = arches - VALID_ARCHES.keys raise "invalid 'depends_on arch' values: #{invalid_arches.inspect}" unless invalid_arches.empty? + @arch.concat(arches.map { |arch| VALID_ARCHES[arch] }) end def x11=(arg) raise "invalid 'depends_on x11' value: #{arg.inspect}" unless [true, false].include?(arg) + @x11 = arg end end diff --git a/Library/Homebrew/cask/dsl/version.rb b/Library/Homebrew/cask/dsl/version.rb index 4e5d608e9e..263ef60006 100644 --- a/Library/Homebrew/cask/dsl/version.rb +++ b/Library/Homebrew/cask/dsl/version.rb @@ -112,6 +112,7 @@ module Cask def version return self if empty? || latest? + self.class.new(yield) end end diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index d33240d234..176a8fe57e 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -151,6 +151,7 @@ module Cask def verify_has_sha odebug "Checking cask has checksum" return unless @cask.sha256 == :no_check + raise CaskNoShasumError, @cask.token end @@ -198,6 +199,7 @@ module Cask artifacts.each do |artifact| next unless artifact.respond_to?(:install_phase) + odebug "Installing artifact of class #{artifact.class}" if artifact.is_a?(Artifact::Binary) @@ -211,6 +213,7 @@ module Cask begin already_installed_artifacts.each do |artifact| next unless artifact.respond_to?(:uninstall_phase) + odebug "Reverting installation of artifact of class #{artifact.class}" artifact.uninstall_phase(command: @command, verbose: verbose?, force: force?) end @@ -236,6 +239,7 @@ module Cask def macos_dependencies return unless @cask.depends_on.macos + if @cask.depends_on.macos.first.is_a?(Array) operator, release = @cask.depends_on.macos.first unless MacOS.version.send(operator, release) @@ -262,11 +266,13 @@ module Cask def arch_dependencies return if @cask.depends_on.arch.nil? + @current_arch ||= { type: Hardware::CPU.type, bits: Hardware::CPU.bits } return if @cask.depends_on.arch.any? do |arch| arch[:type] == @current_arch[:type] && Array(arch[:bits]).include?(@current_arch[:bits]) end + raise CaskError, "Cask #{@cask} depends on hardware architecture being one of " \ "[#{@cask.depends_on.arch.map(&:to_s).join(", ")}], " \ @@ -362,6 +368,7 @@ module Cask # TODO: logically could be in a separate class def enable_accessibility_access return unless @cask.accessibility_access + ohai "Enabling accessibility access" if MacOS.version <= :mountain_lion @command.run!( @@ -402,6 +409,7 @@ module Cask def disable_accessibility_access return unless @cask.accessibility_access + if MacOS.version >= :mavericks && MacOS.version <= :el_capitan ohai "Disabling accessibility access" @command.run!("/usr/bin/sqlite3", @@ -480,6 +488,7 @@ module Cask artifacts.each do |artifact| next unless artifact.respond_to?(:uninstall_phase) + odebug "Un-installing artifact of class #{artifact.class}" artifact.uninstall_phase(command: @command, verbose: verbose?, skip: clear, force: force?) end @@ -502,11 +511,13 @@ module Cask def backup_path return if @cask.staged_path.nil? + Pathname("#{@cask.staged_path}.upgrading") end def backup_metadata_path return if @cask.metadata_versioned_path.nil? + Pathname("#{@cask.metadata_versioned_path}.upgrading") end diff --git a/Library/Homebrew/cask/pkg.rb b/Library/Homebrew/cask/pkg.rb index 4797a5c875..b8b37c114e 100644 --- a/Library/Homebrew/cask/pkg.rb +++ b/Library/Homebrew/cask/pkg.rb @@ -99,6 +99,7 @@ module Cask def rmdir(path) return unless path.children.empty? + if path.symlink? @command.run!("/bin/rm", args: ["-f", "--", path], sudo: true) else @@ -125,6 +126,7 @@ module Cask def clean_ds_store(dir) return unless (ds_store = dir.join(".DS_Store")).exist? + @command.run!("/bin/rm", args: ["--", ds_store], sudo: true) end diff --git a/Library/Homebrew/cask/staged.rb b/Library/Homebrew/cask/staged.rb index 2330427217..a8b6ee86e7 100644 --- a/Library/Homebrew/cask/staged.rb +++ b/Library/Homebrew/cask/staged.rb @@ -26,6 +26,7 @@ module Cask def set_permissions(paths, permissions_str) full_paths = remove_nonexistent(paths) return if full_paths.empty? + @command.run!("/bin/chmod", args: ["-R", "--", permissions_str] + full_paths, sudo: false) end @@ -33,6 +34,7 @@ module Cask 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) diff --git a/Library/Homebrew/cask/url.rb b/Library/Homebrew/cask/url.rb index f42321385a..678d795696 100644 --- a/Library/Homebrew/cask/url.rb +++ b/Library/Homebrew/cask/url.rb @@ -18,6 +18,7 @@ class URL ATTRIBUTES.each do |attribute| next unless options.key?(attribute) + instance_variable_set("@#{attribute}", options[attribute]) end diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb index c14def5089..6546eb2f76 100644 --- a/Library/Homebrew/cleanup.rb +++ b/Library/Homebrew/cleanup.rb @@ -57,6 +57,7 @@ module CleanupRefinement def stale?(scrub = false) return false unless resolved_path.file? + stale_formula?(scrub) || stale_cask?(scrub) end @@ -162,6 +163,7 @@ module Homebrew cleanup_cache cleanup_logs return if dry_run? + rm_ds_store else args.each do |arg| @@ -211,6 +213,7 @@ module Homebrew def cleanup_logs return unless HOMEBREW_LOGS.directory? + HOMEBREW_LOGS.subdirs.each do |dir| cleanup_path(dir) { dir.rmtree } if dir.prune?(days || DEFAULT_LOG_DAYS) end diff --git a/Library/Homebrew/cli_parser.rb b/Library/Homebrew/cli_parser.rb index be8962363f..fb260d35d8 100644 --- a/Library/Homebrew/cli_parser.rb +++ b/Library/Homebrew/cli_parser.rb @@ -115,6 +115,7 @@ module Homebrew end return if depends_on.nil? + primary = option_to_name(depends_on) @constraints << [primary, secondary, :optional] end @@ -139,6 +140,7 @@ module Homebrew end next if violations.count < 2 + raise OptionConflictError, violations.map(&method(:name_to_option)) end end @@ -147,6 +149,7 @@ module Homebrew @conflicts.each do |mutually_exclusive_options_group| @constraints.each do |p, s| next unless Set[p, s].subset?(Set[*mutually_exclusive_options_group]) + raise InvalidConstraintError.new(p, s) end end diff --git a/Library/Homebrew/cmd/analytics.rb b/Library/Homebrew/cmd/analytics.rb index 0f56cd675f..da69de03b3 100644 --- a/Library/Homebrew/cmd/analytics.rb +++ b/Library/Homebrew/cmd/analytics.rb @@ -15,6 +15,7 @@ module Homebrew config_file = HOMEBREW_REPOSITORY/".git/config" raise UsageError if ARGV.named.size > 1 + case ARGV.named.first when nil, "state" analyticsdisabled = \ diff --git a/Library/Homebrew/cmd/commands.rb b/Library/Homebrew/cmd/commands.rb index 2443734821..9644a1dee2 100644 --- a/Library/Homebrew/cmd/commands.rb +++ b/Library/Homebrew/cmd/commands.rb @@ -48,8 +48,10 @@ module Homebrew cmd_paths.each_with_object([]) do |path, cmds| Dir["#{path}/brew-*"].each do |file| next unless File.executable?(file) + cmd = File.basename(file, ".rb")[5..-1] next if cmd.include?(".") + cmds << cmd end end.sort diff --git a/Library/Homebrew/cmd/deps.rb b/Library/Homebrew/cmd/deps.rb index c1ccb7ca84..c947d8ac14 100644 --- a/Library/Homebrew/cmd/deps.rb +++ b/Library/Homebrew/cmd/deps.rb @@ -73,6 +73,7 @@ module Homebrew puts_deps_tree Formula.installed.sort, !ARGV.one? else raise FormulaUnspecifiedError if ARGV.named.empty? + puts_deps_tree ARGV.formulae, !ARGV.one? end return @@ -92,6 +93,7 @@ module Homebrew if ARGV.named.empty? raise FormulaUnspecifiedError unless mode.installed? + puts_deps Formula.installed.sort return end @@ -107,6 +109,7 @@ module Homebrew def condense_requirements(deps) return deps if ARGV.include?("--include-requirements") + deps.select { |dep| dep.is_a? Dependency } end diff --git a/Library/Homebrew/cmd/desc.rb b/Library/Homebrew/cmd/desc.rb index 1a75371a02..a576f7f1a4 100644 --- a/Library/Homebrew/cmd/desc.rb +++ b/Library/Homebrew/cmd/desc.rb @@ -24,6 +24,7 @@ module Homebrew if search_type.empty? raise FormulaUnspecifiedError if ARGV.named.empty? + desc = {} ARGV.formulae.each { |f| desc[f.full_name] = f.desc } results = Descriptions.new(desc) diff --git a/Library/Homebrew/cmd/doctor.rb b/Library/Homebrew/cmd/doctor.rb index 216987077c..1b36e99e24 100644 --- a/Library/Homebrew/cmd/doctor.rb +++ b/Library/Homebrew/cmd/doctor.rb @@ -45,6 +45,7 @@ module Homebrew out = checks.send(method) next if out.nil? || out.empty? + if first_warning $stderr.puts <<~EOS #{Tty.bold}Please note that these warnings are just used to help the Homebrew maintainers diff --git a/Library/Homebrew/cmd/fetch.rb b/Library/Homebrew/cmd/fetch.rb index c518600e9c..892c6426d3 100644 --- a/Library/Homebrew/cmd/fetch.rb +++ b/Library/Homebrew/cmd/fetch.rb @@ -54,6 +54,7 @@ module Homebrew raise rescue => e raise if ARGV.homebrew_developer? + fetched_bottle = false onoe e.message opoo "Bottle fetch failed: fetching the source." @@ -63,6 +64,7 @@ module Homebrew end next if fetched_bottle + fetch_formula(f) f.resources.each do |r| diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb index df87b327c8..2afad99ec3 100644 --- a/Library/Homebrew/cmd/gist-logs.rb +++ b/Library/Homebrew/cmd/gist-logs.rb @@ -106,6 +106,7 @@ module Homebrew end end raise "No logs." if logs.empty? + logs end diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index ece72498fd..3a2dcb01d7 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -171,6 +171,7 @@ module Homebrew %w[build required recommended optional].map do |type| reqs = f.requirements.select(&:"#{type}?") next if reqs.to_a.empty? + puts "#{type.capitalize}: #{decorate_requirements(reqs)}" end end @@ -243,6 +244,7 @@ module Homebrew def dep_display_s(dep) return dep.name if dep.option_tags.empty? + "#{dep.name} #{dep.option_tags.map { |o| "--#{o}" }.join(" ")}" end end diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 6a35ad7fbe..d14eb80c6b 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -98,6 +98,7 @@ module Homebrew if name !~ HOMEBREW_TAP_FORMULA_REGEX && name !~ HOMEBREW_CASK_TAP_CASK_REGEX next end + tap = Tap.fetch(Regexp.last_match(1), Regexp.last_match(2)) tap.install unless tap.installed? end @@ -237,6 +238,7 @@ module Homebrew # Even if we don't install this formula mark it as no longer just # installed as a dependency. next unless f.opt_prefix.directory? + keg = Keg.new(f.opt_prefix.resolved_path) tab = Tab.for_keg(keg) unless tab.installed_on_request @@ -246,6 +248,7 @@ module Homebrew end return if formulae.empty? + Install.perform_preinstall_checks formulae.each do |f| @@ -288,6 +291,7 @@ module Homebrew # Do not search taps if the formula name is qualified return if e.name.include?("/") + ohai "Searching taps..." taps_search_results = search_taps(e.name)[:formulae] case taps_search_results.length diff --git a/Library/Homebrew/cmd/list.rb b/Library/Homebrew/cmd/list.rb index 260f1cc078..3e1aa57ba2 100644 --- a/Library/Homebrew/cmd/list.rb +++ b/Library/Homebrew/cmd/list.rb @@ -47,6 +47,7 @@ module Homebrew # Things below use the CELLAR, which doesn't until the first formula is installed. unless HOMEBREW_CELLAR.exist? raise NoSuchKegError, ARGV.named.first unless ARGV.named.empty? + return end @@ -56,6 +57,7 @@ module Homebrew if args.full_name? full_names = Formula.installed.map(&:full_name).sort(&tap_and_name_comparison) return if full_names.empty? + puts Formatter.columns(full_names) else ENV["CLICOLOR"] = nil @@ -136,6 +138,7 @@ module Homebrew names.sort.each do |d| versions = d.subdirs.map { |pn| pn.basename.to_s } next if args.multiple? && versions.length < 2 + puts "#{d.basename} #{versions * " "}" end end diff --git a/Library/Homebrew/cmd/options.rb b/Library/Homebrew/cmd/options.rb index 6bb6afafe9..9a54d9c37b 100644 --- a/Library/Homebrew/cmd/options.rb +++ b/Library/Homebrew/cmd/options.rb @@ -21,6 +21,7 @@ module Homebrew puts_options Formula.installed.sort else raise FormulaUnspecifiedError if ARGV.named.empty? + puts_options ARGV.formulae end end @@ -28,6 +29,7 @@ module Homebrew def puts_options(formulae) formulae.each do |f| next if f.options.empty? + if ARGV.include? "--compact" puts f.options.as_flags.sort * " " else diff --git a/Library/Homebrew/cmd/prune.rb b/Library/Homebrew/cmd/prune.rb index ad482ed56e..b7aaf7612a 100644 --- a/Library/Homebrew/cmd/prune.rb +++ b/Library/Homebrew/cmd/prune.rb @@ -17,6 +17,7 @@ module Homebrew Keg::PRUNEABLE_DIRECTORIES.each do |dir| next unless dir.directory? + dir.find do |path| path.extend(ObserverPathnameExtension) if path.symlink? diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index dd8ecbbea4..bc1bce435f 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -117,12 +117,14 @@ module Homebrew return unless $stdout.tty? return if args.remaining.empty? + metacharacters = %w[\\ | ( ) [ ] { } ^ $ * + ?].freeze return unless metacharacters.any? do |char| args.remaining.any? do |arg| arg.include?(char) && !arg.start_with?("/") end end + ohai <<~EOS Did you mean to perform a regular expression search? Surround your query with /slashes/ to search locally by regex. diff --git a/Library/Homebrew/cmd/tap-pin.rb b/Library/Homebrew/cmd/tap-pin.rb index 505720f30d..6d18eba4d6 100644 --- a/Library/Homebrew/cmd/tap-pin.rb +++ b/Library/Homebrew/cmd/tap-pin.rb @@ -9,6 +9,7 @@ module Homebrew ARGV.named.each do |name| tap = Tap.fetch(name) raise "pinning #{tap} is not allowed" if tap.core_tap? + tap.pin ohai "Pinned #{tap}" end diff --git a/Library/Homebrew/cmd/tap-unpin.rb b/Library/Homebrew/cmd/tap-unpin.rb index 0c7c9ee020..a89960f429 100644 --- a/Library/Homebrew/cmd/tap-unpin.rb +++ b/Library/Homebrew/cmd/tap-unpin.rb @@ -8,6 +8,7 @@ module Homebrew ARGV.named.each do |name| tap = Tap.fetch(name) raise "unpinning #{tap} is not allowed" if tap.core_tap? + tap.unpin ohai "Unpinned #{tap}" end diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb index af0efaf626..b82d7e8155 100644 --- a/Library/Homebrew/cmd/uninstall.rb +++ b/Library/Homebrew/cmd/uninstall.rb @@ -22,6 +22,7 @@ module Homebrew Hash[ARGV.named.map do |name| rack = Formulary.to_rack(name) next unless rack.directory? + [rack, rack.subdirs.map { |d| Keg.new(d) }] end] else diff --git a/Library/Homebrew/cmd/unpack.rb b/Library/Homebrew/cmd/unpack.rb index aee4ea2ebf..72e15df258 100644 --- a/Library/Homebrew/cmd/unpack.rb +++ b/Library/Homebrew/cmd/unpack.rb @@ -33,6 +33,7 @@ module Homebrew if stage_dir.exist? raise "Destination #{stage_dir} already exists!" unless ARGV.force? + rm_rf stage_dir end @@ -46,6 +47,7 @@ module Homebrew ENV["VERBOSE"] = nil next unless ARGV.git? + ohai "Setting up git repository" cd stage_dir system "git", "init", "-q" diff --git a/Library/Homebrew/cmd/untap.rb b/Library/Homebrew/cmd/untap.rb index 1b4bf109dd..fb2c77668f 100644 --- a/Library/Homebrew/cmd/untap.rb +++ b/Library/Homebrew/cmd/untap.rb @@ -10,6 +10,7 @@ module Homebrew ARGV.named.each do |tapname| tap = Tap.fetch(tapname) raise "untapping #{tap} is not allowed" if tap.core_tap? + tap.uninstall end end diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index 38d59a0f53..f13869b400 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -92,6 +92,7 @@ module Homebrew updated_taps = [] Tap.each do |tap| next unless tap.git? + begin reporter = Reporter.new(tap) rescue Reporter::ReporterRevisionUnsetError => e @@ -150,8 +151,10 @@ module Homebrew def install_core_tap_if_necessary return if ENV["HOMEBREW_UPDATE_TEST"] + core_tap = CoreTap.instance return if core_tap.installed? + CoreTap.ensure_installed! revision = core_tap.git_head ENV["HOMEBREW_UPDATE_BEFORE_HOMEBREW_HOMEBREW_CORE"] = revision @@ -236,6 +239,7 @@ class Reporter dst_full_name = tap.formula_file_to_name(dst) # Don't report formulae that are moved within a tap but not renamed next if src_full_name == dst_full_name + @report[:D] << src_full_name @report[:A] << dst_full_name end @@ -302,6 +306,7 @@ class Reporter # This means it is a Cask if report[:DC].include? full_name next unless (HOMEBREW_PREFIX/"Caskroom"/new_name).exist? + new_tap = Tap.fetch(new_tap_name) new_tap.install unless new_tap.installed? ohai "#{name} has been moved to Homebrew.", <<~EOS @@ -309,6 +314,7 @@ class Reporter brew cask uninstall --force #{name} EOS next if (HOMEBREW_CELLAR/new_name.split("/").last).directory? + ohai "Installing #{new_name}..." system HOMEBREW_BREW_FILE, "install", new_full_name begin @@ -322,8 +328,10 @@ class Reporter end next unless (dir = HOMEBREW_CELLAR/name).exist? # skip if formula is not installed. + tabs = dir.subdirs.map { |d| Tab.for_keg(Keg.new(d)) } next unless tabs.first.tap == tap # skip if installed formula is not from this tap. + new_tap = Tap.fetch(new_tap_name) # For formulae migrated to cask: Auto-install cask or provide install instructions. if new_tap_name.start_with?("homebrew/cask") @@ -445,6 +453,7 @@ class ReporterHub end.compact return if formulae.empty? + # Dump formula list. ohai title puts Formatter.columns(formulae.sort) diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index 858ca47e10..f02fe9ef26 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -109,6 +109,7 @@ module Homebrew upgrade_formula(f) next if !ARGV.include?("--cleanup") && !ENV["HOMEBREW_UPGRADE_CLEANUP"] next unless f.installed? + Cleanup.new.cleanup_formula(f) rescue UnsatisfiedRequirements => e Homebrew.failed = true diff --git a/Library/Homebrew/cmd/uses.rb b/Library/Homebrew/cmd/uses.rb index bfc81f040a..0b947cced6 100644 --- a/Library/Homebrew/cmd/uses.rb +++ b/Library/Homebrew/cmd/uses.rb @@ -76,6 +76,7 @@ module Homebrew end return if uses.empty? + puts Formatter.columns(uses.map(&:full_name).sort) odie "Missing formulae should not have dependents!" if used_formulae_missing end diff --git a/Library/Homebrew/compat/cask/cmd/--version.rb b/Library/Homebrew/compat/cask/cmd/--version.rb index 25f9302054..700d9ac11a 100644 --- a/Library/Homebrew/compat/cask/cmd/--version.rb +++ b/Library/Homebrew/compat/cask/cmd/--version.rb @@ -11,6 +11,7 @@ module Cask def initialize(*) super return if args.empty? + raise ArgumentError, "#{self.class.command_name} does not take arguments." end diff --git a/Library/Homebrew/constants.rb b/Library/Homebrew/constants.rb index fc2b322c97..895b12bd3c 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.58.2" -HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.21.0" # has to be updated when RuboCop version changes +HOMEBREW_RUBOCOP_VERSION = "0.59.1" +HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.22.0" # has to be updated when RuboCop version changes diff --git a/Library/Homebrew/cxxstdlib.rb b/Library/Homebrew/cxxstdlib.rb index f4b0162007..166b86209f 100644 --- a/Library/Homebrew/cxxstdlib.rb +++ b/Library/Homebrew/cxxstdlib.rb @@ -16,6 +16,7 @@ class CxxStdlib if type && ![:libstdcxx, :libcxx].include?(type) raise ArgumentError, "Invalid C++ stdlib type: #{type}" end + klass = (compiler.to_s =~ GNU_GCC_REGEXP) ? GnuStdlib : AppleStdlib klass.new(type, compiler) end diff --git a/Library/Homebrew/dependable.rb b/Library/Homebrew/dependable.rb index 3639926dbe..ce3b8f426d 100644 --- a/Library/Homebrew/dependable.rb +++ b/Library/Homebrew/dependable.rb @@ -35,12 +35,14 @@ module Dependable def prune_from_option?(build) return if !optional? && !recommended? + build.without?(self) end def prune_if_build_and_not_dependent?(dependent, formula = nil) return false unless build? return dependent.installed? unless formula + dependent != formula end end diff --git a/Library/Homebrew/dependencies.rb b/Library/Homebrew/dependencies.rb index 36348a14d4..0ca5d9ea88 100644 --- a/Library/Homebrew/dependencies.rb +++ b/Library/Homebrew/dependencies.rb @@ -41,6 +41,7 @@ class Requirements < DelegateClass(Set) if other.is_a?(Comparable) grep(other.class) do |req| return self if req > other + delete(req) end end @@ -126,6 +127,7 @@ module Homebrew def reject_ignores(dependables, ignores, includes) dependables.reject do |dep| next false unless ignores.any? { |ignore| dep.send(ignore) } + includes.none? { |include| dep.send(include) } end end diff --git a/Library/Homebrew/dependency.rb b/Library/Homebrew/dependency.rb index 0b6801788e..126df977e1 100644 --- a/Library/Homebrew/dependency.rb +++ b/Library/Homebrew/dependency.rb @@ -93,11 +93,13 @@ class Dependency next when :skip next if @expand_stack.include? dep.name + expanded_deps.concat(expand(dep.to_formula, &block)) when :keep_but_prune_recursive_deps expanded_deps << dep else next if @expand_stack.include? dep.name + expanded_deps.concat(expand(dep.to_formula, &block)) expanded_deps << dep end @@ -167,6 +169,7 @@ class Dependency def merge_temporality(deps) # Means both build and runtime dependency. return [] unless deps.all?(&:build?) + [:build] end end diff --git a/Library/Homebrew/dependency_collector.rb b/Library/Homebrew/dependency_collector.rb index 1a00c72012..9f22429ca5 100644 --- a/Library/Homebrew/dependency_collector.rb +++ b/Library/Homebrew/dependency_collector.rb @@ -53,11 +53,13 @@ class DependencyCollector def git_dep_if_needed(tags) return if Utils.git_available? + Dependency.new("git", tags) end def subversion_dep_if_needed(tags) return if Utils.svn_available? + Dependency.new("subversion", tags) end diff --git a/Library/Homebrew/descriptions.rb b/Library/Homebrew/descriptions.rb index b14833e3d0..96b7fe6982 100644 --- a/Library/Homebrew/descriptions.rb +++ b/Library/Homebrew/descriptions.rb @@ -39,10 +39,12 @@ class Descriptions # repos were updated more recently than it was. def self.cache_fresh? return false unless CACHE_FILE.exist? + cache_mtime = File.mtime(CACHE_FILE) Tap.each do |tap| next unless tap.git? + repo_mtime = File.mtime(tap.path/".git/refs/heads/master") return false if repo_mtime > cache_mtime end @@ -93,6 +95,7 @@ class Descriptions # the cache. Save the updated cache to disk, unless explicitly told not to. def self.uncache_formulae(formula_names, options = { save: true }) return unless cache + formula_names.each { |name| @cache.delete(name) } save_cache if options[:save] end diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 0fda62b902..18efdd7ee2 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -126,6 +126,7 @@ module Homebrew fa = FormulaAuditor.new(f, options) fa.audit next if fa.problems.empty? && fa.new_formula_problems.empty? + fa.problems formula_count += 1 problem_count += fa.problems.size @@ -240,9 +241,11 @@ module Homebrew def audit_style return unless @style_offenses + @style_offenses.each do |offense| if offense.cop_name.start_with?("NewFormulaAudit") next if formula.versioned_formula? + new_formula_problem offense.to_s(display_cop_name: @display_cop_names) next end @@ -430,6 +433,7 @@ module Homebrew next unless @new_formula next unless @official_tap + if dep.tags.include?(:recommended) || dep.tags.include?(:optional) new_formula_problem options_message end @@ -437,6 +441,7 @@ module Homebrew next unless @new_formula next unless @official_tap + if spec.requirements.map(&:recommended?).any? || spec.requirements.map(&:optional?).any? new_formula_problem options_message end @@ -487,6 +492,7 @@ module Homebrew end return unless reason.end_with?(".") + problem "keg_only reason should not end with a period." end @@ -498,6 +504,7 @@ module Homebrew 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, @@ -518,6 +525,7 @@ module Homebrew leafnode ] return if bottle_disabled_whitelist.include?(formula.name) + problem "Formulae should not use `bottle :disabled`" if @official_tap end end @@ -549,6 +557,7 @@ module Homebrew end return if Date.parse(metadata["created_at"]) <= (Date.today - 30) + new_formula_problem "GitHub repository too new (<30 days old)" end @@ -577,6 +586,7 @@ module Homebrew next if spec.patches.empty? next unless @new_formula + new_formula_problem( "Formulae should not require patches to build. " \ "Patches should be submitted and accepted upstream first.", @@ -585,6 +595,7 @@ module Homebrew %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" @@ -627,6 +638,7 @@ module Homebrew throttled.each_slice(2).to_a.map do |a, b| next if formula.stable.nil? + version = formula.stable.version.to_s.split(".").last.to_i if @strict && a == formula.name && version.modulo(b.to_i).nonzero? problem "should only be updated every #{b} releases on multiples of #{b}" @@ -675,10 +687,12 @@ module Homebrew 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 @@ -701,6 +715,7 @@ module Homebrew 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 " \ @@ -743,6 +758,7 @@ module Homebrew map_includes_version = spec_version_scheme_map.key?(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 @@ -777,6 +793,7 @@ module Homebrew 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| @@ -848,6 +865,7 @@ module Homebrew 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 @@ -976,6 +994,7 @@ module Homebrew end return unless version.to_s =~ /_\d+$/ + problem "version #{version} should not end with an underline and a number" end @@ -1011,6 +1030,7 @@ module Homebrew end return unless url_strategy == DownloadStrategyDetector.detect("", using) + problem "Redundant :using value in URL" end @@ -1040,6 +1060,7 @@ module Homebrew end return unless @online + urls.each do |url| next if !@strict && mirrors.include?(url) @@ -1048,6 +1069,7 @@ module Homebrew # 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 @@ -1058,6 +1080,7 @@ module Homebrew 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 diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index d9439ea276..8ac632277a 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -86,6 +86,7 @@ module Homebrew end return merge if args.merge? + ensure_relocation_formulae_installed! ARGV.resolved_formulae.each do |f| bottle_formula f @@ -95,6 +96,7 @@ module Homebrew def ensure_relocation_formulae_installed! Keg.relocation_formulae.each do |f| next if Formula[f].installed? + ohai "Installing #{f}..." safe_system HOMEBREW_BREW_FILE, "install", f end @@ -140,6 +142,7 @@ module Homebrew str = io.readline.chomp next if ignores.any? { |i| i =~ str } next unless str.include? string + offset, match = str.split(" ", 2) next if linked_libraries.include? match # Don't bother reporting a string if it was found by otool @@ -149,6 +152,7 @@ module Homebrew end next unless args.verbose? && !text_matches.empty? + print_filename.call(string, file) text_matches.first(MAXIMUM_STRING_MATCHES).each do |match, offset| puts " #{Tty.bold}-->#{Tty.reset} match '#{match}' at offset #{Tty.bold}0x#{offset}#{Tty.reset}" @@ -166,6 +170,7 @@ module Homebrew absolute_symlinks_start_with_string = [] keg.find do |pn| next unless pn.symlink? && (link = pn.readlink).absolute? + absolute_symlinks_start_with_string << pn if link.to_s.start_with?(string) end @@ -376,6 +381,7 @@ module Homebrew puts output return unless args.json? + tag = Utils::Bottles.tag.to_s tag += "_or_later" if args.or_later? json = { @@ -444,6 +450,7 @@ module Homebrew bottle_block_contents.lines.each do |line| line = line.strip next if line.empty? + key, old_value_original, _, tag = line.split " ", 4 valid_key = %w[root_url prefix cellar rebuild sha1 sha256].include? key next unless valid_key @@ -465,6 +472,7 @@ module Homebrew value = value_original.to_s next if key == "cellar" && old_value == "any" && value == "any_skip_relocation" next unless old_value.empty? || value != old_value + old_value = old_value_original.inspect value = value_original.inspect mismatches << "#{key}: old: #{old_value}, new: #{value}" diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 5a2112862e..5dc47299ca 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -378,11 +378,13 @@ module Homebrew unless old raise "No old value for new value #{new}! Did you pass the wrong arguments?" end + contents.gsub!(old, new) end unless contents.errors.empty? raise Utils::InreplaceError, path => contents.errors end + path.atomic_write(contents) if args.write? contents else @@ -394,6 +396,7 @@ module Homebrew unless old raise "No old value for new value #{new}! Did you pass the wrong arguments?" end + s.gsub!(old, new) end end @@ -425,6 +428,7 @@ module Homebrew pull_requests = fetch_pull_requests(formula) return unless pull_requests return if pull_requests.empty? + duplicates_message = <<~EOS These open pull requests may be duplicates: #{pull_requests.map { |pr| "#{pr["title"]} #{pr["html_url"]}" }.join("\n")} diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb index 6417605509..0323722bcf 100644 --- a/Library/Homebrew/dev-cmd/create.rb +++ b/Library/Homebrew/dev-cmd/create.rb @@ -58,6 +58,7 @@ module Homebrew fc.version = version fc.tap = Tap.fetch(tap || "homebrew/core") raise TapUnavailableError, tap unless fc.tap.installed? + fc.url = url fc.mode = if args.cmake? diff --git a/Library/Homebrew/dev-cmd/edit.rb b/Library/Homebrew/dev-cmd/edit.rb index ab694752db..62def730db 100644 --- a/Library/Homebrew/dev-cmd/edit.rb +++ b/Library/Homebrew/dev-cmd/edit.rb @@ -32,6 +32,7 @@ module Homebrew paths ||= ARGV.named.map do |name| path = Formulary.path(name) raise FormulaUnavailableError, name if !path.file? && !args.force? + path end diff --git a/Library/Homebrew/dev-cmd/extract.rb b/Library/Homebrew/dev-cmd/extract.rb index 9a5298aaaa..cce25a171e 100644 --- a/Library/Homebrew/dev-cmd/extract.rb +++ b/Library/Homebrew/dev-cmd/extract.rb @@ -127,10 +127,12 @@ module Homebrew rev = Git.last_revision_commit_of_file(repo, file, before_commit: "#{rev}~1") break if rev.empty? break unless Git.last_revision_of_file(repo, file, before_commit: rev).empty? + ohai "Skipping revision #{rev} - file is empty at this revision" if ARGV.debug? end test_formula = formula_at_revision(repo, name, file, rev) break if test_formula.nil? || test_formula.version == version + ohai "Trying #{test_formula.version} from revision #{rev} against desired #{version}" if ARGV.debug? end odie "Could not find #{name}! The formula or version may not have existed." if test_formula.nil? @@ -172,6 +174,7 @@ module Homebrew # @private def formula_at_revision(repo, name, file, rev) return if rev.empty? + contents = Git.last_revision_of_file(repo, file, before_commit: rev) contents.gsub!("@url=", "url ") contents.gsub!("require 'brewkit'", "require 'formula'") diff --git a/Library/Homebrew/dev-cmd/formula.rb b/Library/Homebrew/dev-cmd/formula.rb index eb6cd087ea..71cecdeb5d 100644 --- a/Library/Homebrew/dev-cmd/formula.rb +++ b/Library/Homebrew/dev-cmd/formula.rb @@ -14,6 +14,7 @@ module Homebrew end raise FormulaUnspecifiedError if ARGV.named.empty? + ARGV.resolved_formulae.each { |f| puts f.path } end end diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb index a498f03ef6..5001da9181 100644 --- a/Library/Homebrew/dev-cmd/pull.rb +++ b/Library/Homebrew/dev-cmd/pull.rb @@ -64,6 +64,7 @@ module GitHub def test_bot_user(user, test_bot) return test_bot if test_bot return "BrewTestBot" if user.casecmp("homebrew").zero? + "#{user.capitalize}TestBot" end end @@ -194,6 +195,7 @@ module Homebrew "--diff-filter=AM", orig_revision, "HEAD", "--", tap.formula_dir.to_s ).each_line do |line| next unless line.end_with? ".rb\n" + name = "#{tap.name}/#{File.basename(line.chomp, ".rb")}" changed_formulae_names << name end @@ -227,6 +229,7 @@ module Homebrew end else next unless f.bottle_defined? + opoo "#{f.full_name} has a bottle: do you need to update it with --bottle?" end end @@ -320,8 +323,10 @@ module Homebrew changed_formulae_names.each do |name| f = Formula[name] next if f.bottle_unneeded? || f.bottle_disabled? + bintray_org = args.bintray_org || tap.user.downcase next unless publish_bottle_file_on_bintray(f, bintray_org, bintray_creds) + published << f.full_name end else @@ -481,6 +486,7 @@ module Homebrew if info.nil? raise "Failed publishing bottle: failed reading formula info for #{f.full_name}" end + unless info.bottle_info_any opoo "No bottle defined in formula #{package}" return false @@ -495,6 +501,7 @@ module Homebrew true rescue => e raise unless @args.warn_on_publish_failure? + onoe e false end @@ -521,14 +528,17 @@ module Homebrew def bottle_tags return [] unless info["bottle"]["stable"] + info["bottle"]["stable"]["files"].keys end def bottle_info(my_bottle_tag = Utils::Bottles.tag) tag_s = my_bottle_tag.to_s return unless info["bottle"]["stable"] + btl_info = info["bottle"]["stable"]["files"][tag_s] return unless btl_info + BottleInfo.new(btl_info["url"], btl_info["sha256"]) end @@ -623,6 +633,7 @@ module Homebrew if retry_count >= max_retries raise "Failed to find published #{f} bottle at #{url}!" end + print(wrote_dots ? "." : "Waiting on Bintray.") wrote_dots = true sleep poll_retry_delay_seconds @@ -647,6 +658,7 @@ module Homebrew if retry_count >= max_curl_retries raise "Failed to download #{f} bottle from #{url}!" end + puts "curl download failed; retrying in #{curl_retry_delay_seconds} sec" sleep curl_retry_delay_seconds curl_retry_delay_seconds *= 2 @@ -663,6 +675,7 @@ module Homebrew headers, = curl_output("--connect-timeout", "15", "--location", "--head", url) status_code = headers.scan(%r{^HTTP\/.* (\d+)}).last.first return if status_code.start_with?("2") + opoo "The Bintray mirror #{url} is not reachable (HTTP status code #{status_code})." opoo "Do you need to upload it with `brew mirror #{name}`?" end diff --git a/Library/Homebrew/dev-cmd/release-notes.rb b/Library/Homebrew/dev-cmd/release-notes.rb index d66d969292..1a6616e9a5 100644 --- a/Library/Homebrew/dev-cmd/release-notes.rb +++ b/Library/Homebrew/dev-cmd/release-notes.rb @@ -25,6 +25,7 @@ module Homebrew [previous_tag, end_ref].each do |ref| next if quiet_system "git", "-C", HOMEBREW_REPOSITORY, "rev-parse", "--verify", "--quiet", ref + odie "Ref #{ref} does not exist!" end diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb index e3b5af1e20..1be9f17640 100644 --- a/Library/Homebrew/dev-cmd/tap-new.rb +++ b/Library/Homebrew/dev-cmd/tap-new.rb @@ -11,6 +11,7 @@ module Homebrew path = tap.path/filename tap.path.mkpath raise "#{path} already exists" if path.exist? + path.write content end diff --git a/Library/Homebrew/dev-cmd/test.rb b/Library/Homebrew/dev-cmd/test.rb index 8e8ceb9824..1e74496dc5 100644 --- a/Library/Homebrew/dev-cmd/test.rb +++ b/Library/Homebrew/dev-cmd/test.rb @@ -49,6 +49,7 @@ module Homebrew missing_test_deps = f.recursive_dependencies do |_, dependency| Dependency.prune if dependency.installed? next if dependency.test? + Dependency.prune if dependency.optional? Dependency.prune if dependency.build? end.map(&:to_s) diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index f26bfed4ab..bfc4694d0b 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -130,6 +130,7 @@ module Homebrew end return if $CHILD_STATUS.success? + Homebrew.failed = true end end diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 56eb943260..ddd47d85f5 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -12,6 +12,7 @@ module Homebrew ff.each do |f| missing_dependencies = f.missing_dependencies(hide: hide) next if missing_dependencies.empty? + yield f.full_name, missing_dependencies if block_given? missing[f.full_name] = missing_dependencies end @@ -32,6 +33,7 @@ module Homebrew vol_index = @volumes.index(vols[0]) # volume not found in volume list return -1 if vol_index.nil? + vol_index end @@ -276,6 +278,7 @@ module Homebrew Keg::PRUNEABLE_DIRECTORIES.each do |d| next unless d.directory? + d.find do |path| if path.symlink? && !path.resolved_path_exists? broken_symlinks << path @@ -408,6 +411,7 @@ module Homebrew def check_for_config_scripts return unless HOMEBREW_CELLAR.exist? + real_cellar = HOMEBREW_CELLAR.realpath scripts = [] @@ -604,6 +608,7 @@ module Homebrew f.installed_prefixes.each do |prefix| prefix.find do |src| next if src == prefix + dst = HOMEBREW_PREFIX + src.relative_path_from(prefix) return true if dst.symlink? && src == dst.resolved_path end @@ -642,6 +647,7 @@ module Homebrew def check_missing_deps return unless HOMEBREW_CELLAR.exist? + missing = Set.new Homebrew::Diagnostic.missing_deps(Formula.installed).each_value do |deps| missing.merge(deps) @@ -659,6 +665,7 @@ module Homebrew def check_git_status return unless Utils.git_available? + HOMEBREW_REPOSITORY.cd do return if `git status --untracked-files=all --porcelain -- Library/Homebrew/ 2>/dev/null`.chomp.empty? end @@ -674,6 +681,7 @@ module Homebrew def check_for_bad_python_symlink return unless which "python" + `python -V 2>&1` =~ /Python (\d+)\./ # This won't be the right warning if we matched nothing at all return if Regexp.last_match(1).nil? @@ -764,14 +772,17 @@ module Homebrew unused_formula_dirs = tap.potential_formula_dirs - [tap.formula_dir] unused_formula_dirs.each do |dir| next unless dir.exist? + dir.children.each do |path| next unless path.extname == ".rb" + bad_tap_files[tap] ||= [] bad_tap_files[tap] << path end end end return if bad_tap_files.empty? + bad_tap_files.keys.map do |tap| <<~EOS Found Ruby file outside #{tap} tap formula directory diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index 7439bf20fe..ee7ba58db1 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -139,6 +139,7 @@ class VCSDownloadStrategy < AbstractDownloadStrategy return unless @ref_type == :tag return unless @revision && current_revision return if current_revision == @revision + raise <<~EOS #{@ref} tag should be #{@revision} but is actually #{current_revision} @@ -194,6 +195,7 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy def symlink_location return @symlink_location if defined?(@symlink_location) + ext = Pathname(parse_basename(url)).extname @symlink_location = @cache/"#{name}--#{version}#{ext}" end @@ -230,6 +232,7 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy def resolved_url_and_basename return @resolved_url_and_basename if defined?(@resolved_url_and_basename) + @resolved_url_and_basename = [url, parse_basename(url)] end @@ -301,6 +304,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy FileUtils.ln_s cached_location.relative_path_from(symlink_location.dirname), symlink_location, force: true rescue CurlDownloadStrategyError raise if urls.empty? + puts "Trying a mirror..." retry end @@ -315,6 +319,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy def resolved_url_and_basename return @resolved_url_and_basename if defined?(@resolved_url_and_basename) + @resolved_url_and_basename = resolve_url_and_basename(url) end @@ -378,6 +383,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy def _curl_opts return { user_agent: meta.fetch(:user_agent) } if meta.key?(:user_agent) + {} end @@ -417,6 +423,7 @@ class CurlApacheMirrorDownloadStrategy < CurlDownloadStrategy def apache_mirrors return @apache_mirrors if defined?(@apache_mirrors) + json, = curl_output("--silent", "--location", "#{url}&asjson=1") @apache_mirrors = JSON.parse(json) rescue JSON::ParserError @@ -472,6 +479,7 @@ class S3DownloadStrategy < CurlDownloadStrategy url !~ %r{^s3://([^.].*?)/(.+)$} raise "Bad S3 URL: " + url end + bucket = Regexp.last_match(1) key = Regexp.last_match(2) @@ -531,6 +539,7 @@ class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy unless @github_token raise CurlDownloadStrategyError, "Environmental variable HOMEBREW_GITHUB_API_TOKEN is required." end + validate_github_repository_access! end @@ -933,6 +942,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy super return unless %r{^https?://github\.com/(?[^/]+)/(?[^/]+)\.git$} =~ @url + @user = user @repo = repo end @@ -972,6 +982,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy else return true unless commit return true unless @last_commit.start_with?(commit) + if multiple_short_commits_exist?(commit) true else @@ -1003,6 +1014,7 @@ class CVSDownloadStrategy < VCSDownloadStrategy cached_location.find do |f| Find.prune if f.directory? && f.basename.to_s == "CVS" next unless f.file? + mtime = f.mtime max_mtime = mtime if mtime > max_mtime end @@ -1110,6 +1122,7 @@ class BazaarDownloadStrategy < VCSDownloadStrategy out, = system_command("bzr", args: ["log", "-l", "1", "--timezone=utc", cached_location]) timestamp = out.chomp raise "Could not get any timestamps from bzr!" if timestamp.blank? + Time.parse(timestamp) end diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 51d85d19ca..59452508df 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -429,6 +429,7 @@ class BuildError < RuntimeError checks.build_error_checks.each do |check| out = checks.send(check) next if out.nil? + puts ofail out end diff --git a/Library/Homebrew/extend/ARGV.rb b/Library/Homebrew/extend/ARGV.rb index 10f680e5e8..a5d8a32802 100644 --- a/Library/Homebrew/extend/ARGV.rb +++ b/Library/Homebrew/extend/ARGV.rb @@ -125,6 +125,7 @@ module HomebrewArgvExtension # @see value def values(name) return unless val = value(name) + val.split(",") end @@ -226,6 +227,7 @@ module HomebrewArgvExtension def build_formula_from_source?(f) return true if build_all_from_source? return false unless build_from_source? || build_bottle? + formulae.any? { |argv_f| argv_f.full_name == f.full_name } end @@ -244,6 +246,7 @@ module HomebrewArgvExtension # eg. `foo -ns -i --bar` has three switches, n, s and i def switch?(char) return false if char.length > 1 + options_only.any? { |arg| arg.scan("-").size == 1 && arg.include?(char) } end diff --git a/Library/Homebrew/extend/ENV.rb b/Library/Homebrew/extend/ENV.rb index 002220764a..e0eee1b753 100644 --- a/Library/Homebrew/extend/ENV.rb +++ b/Library/Homebrew/extend/ENV.rb @@ -30,6 +30,7 @@ module EnvActivation def clear_sensitive_environment! each_key do |key| next unless /(cookie|key|token|password)/i =~ key + delete key end end diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb index 328e1a6983..1f5bb384d6 100644 --- a/Library/Homebrew/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/ENV/shared.rb @@ -95,6 +95,7 @@ module SharedEnvExtension # (e.g.
ENV.prepend_path "PATH", which("emacs").dirname
) def prepend_path(key, path) return if %w[/usr/bin /bin /usr/sbin /sbin].include? path.to_s + self[key] = PATH.new(self[key]).prepend(path) end @@ -106,8 +107,10 @@ module SharedEnvExtension def remove(keys, value) return if value.nil? + Array(keys).each do |key| next unless self[key] + self[key] = self[key].sub(value, "") delete(key) if self[key].empty? end @@ -223,6 +226,7 @@ module SharedEnvExtension # building with an alternative Fortran compiler without optimization flags, # despite it often being the Homebrew-provided one set up in the first call. return if @fortran_setup_done + @fortran_setup_done = true flags = [] @@ -294,6 +298,7 @@ module SharedEnvExtension end return if gcc_formula.opt_prefix.exist? + raise <<~EOS The requested Homebrew GCC was not installed. You must: brew install #{gcc_formula.full_name} @@ -313,6 +318,7 @@ module SharedEnvExtension # @private def compiler_with_cxx11_support?(cc) return if compiler_any_clang?(cc) + version = cc[/^gcc-(\d+(?:\.\d+)?)$/, 1] version && Version.create(version) >= Version.create("4.8") end @@ -344,6 +350,7 @@ module SharedEnvExtension def check_for_compiler_universal_support return unless homebrew_cc =~ GNU_GCC_REGEXP + raise "Non-Apple GCC can't build universal binaries" end end diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index 5a152f0d55..1c03f4317b 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -46,6 +46,7 @@ module Stdenv send(compiler) return unless cc =~ GNU_GCC_REGEXP + gcc_formula = gcc_version_formula($&) append_path "PATH", gcc_formula.opt_bin.to_s end @@ -159,6 +160,7 @@ module Stdenv return if compiler_any_clang? return unless Hardware.is_32_bit? + # Can't mix "-march" for a 32-bit CPU with "-arch x86_64" replace_in_cflags(/-march=\S*/, "-Xarch_#{Hardware::CPU.arch_32_bit} \\0") end diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb index 410d7f64bf..8d7e44b44a 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -278,6 +278,7 @@ module Superenv # GCC doesn't accept "-march" for a 32-bit CPU with "-arch x86_64" return if compiler_any_clang? return unless Hardware::CPU.is_32_bit? + self["HOMEBREW_OPTFLAGS"] = self["HOMEBREW_OPTFLAGS"].sub( /-march=\S*/, "-Xarch_#{Hardware::CPU.arch_32_bit} \\0", diff --git a/Library/Homebrew/extend/git_repository.rb b/Library/Homebrew/extend/git_repository.rb index 0b5a6b87f6..9bfb6cf43c 100644 --- a/Library/Homebrew/extend/git_repository.rb +++ b/Library/Homebrew/extend/git_repository.rb @@ -8,36 +8,43 @@ module GitRepositoryExtension def git_origin return unless git? && Utils.git_available? + Utils.popen_read("git", "config", "--get", "remote.origin.url", chdir: self).chuzzle end def git_origin=(origin) return unless git? && Utils.git_available? + safe_system "git", "remote", "set-url", "origin", origin, chdir: self end def git_head return unless git? && Utils.git_available? + Utils.popen_read("git", "rev-parse", "--verify", "-q", "HEAD", chdir: self).chuzzle end def git_short_head return unless git? && Utils.git_available? + Utils.popen_read("git", "rev-parse", "--short=4", "--verify", "-q", "HEAD", chdir: self).chuzzle end def git_last_commit return unless git? && Utils.git_available? + Utils.popen_read("git", "show", "-s", "--format=%cr", "HEAD", chdir: self).chuzzle end def git_branch return unless git? && Utils.git_available? + Utils.popen_read("git", "rev-parse", "--abbrev-ref", "HEAD", chdir: self).chuzzle end def git_last_commit_date return unless git? && Utils.git_available? + Utils.popen_read("git", "show", "-s", "--format=%cd", "--date=short", "HEAD", chdir: self).chuzzle end end diff --git a/Library/Homebrew/extend/hash_validator.rb b/Library/Homebrew/extend/hash_validator.rb index c5a046f9b6..1a00d3fa1e 100644 --- a/Library/Homebrew/extend/hash_validator.rb +++ b/Library/Homebrew/extend/hash_validator.rb @@ -3,6 +3,7 @@ module HashValidator def assert_valid_keys!(*valid_keys) unknown_keys = keys - valid_keys return if unknown_keys.empty? + raise ArgumentError, "invalid keys: #{unknown_keys.map(&:inspect).join(", ")}" end end diff --git a/Library/Homebrew/extend/io.rb b/Library/Homebrew/extend/io.rb index 53bca196e1..70ded984f7 100644 --- a/Library/Homebrew/extend/io.rb +++ b/Library/Homebrew/extend/io.rb @@ -5,6 +5,7 @@ class IO loop do break if buffer == sep + read_nonblock(1, buffer) line.concat(buffer) end @@ -12,6 +13,7 @@ class IO line rescue IO::WaitReadable, EOFError => e raise e if line.empty? + line end end diff --git a/Library/Homebrew/extend/os/linux/diagnostic.rb b/Library/Homebrew/extend/os/linux/diagnostic.rb index f4bff47a84..12c5e0a162 100644 --- a/Library/Homebrew/extend/os/linux/diagnostic.rb +++ b/Library/Homebrew/extend/os/linux/diagnostic.rb @@ -8,6 +8,7 @@ module Homebrew def check_tmpdir_sticky_bit message = generic_check_tmpdir_sticky_bit return if message.nil? + message + <<~EOS If you don't have administrative privileges on this machine, create a directory and set the HOMEBREW_TEMP environment variable, @@ -23,6 +24,7 @@ module Homebrew f.chmod 0700 f.close return if system f.path + <<~EOS.undent The directory #{HOMEBREW_TEMP} does not permit executing programs. It is likely mounted as "noexec". Please set HOMEBREW_TEMP @@ -37,6 +39,7 @@ module Homebrew def check_xdg_data_dirs return if ENV["XDG_DATA_DIRS"].blank? return if ENV["XDG_DATA_DIRS"].split("/").include?(HOMEBREW_PREFIX/"share") + <<~EOS Homebrew's share was not found in your XDG_DATA_DIRS but you have this variable set to include other locations. diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb index 043a1d8065..b8e1f1dd93 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb @@ -36,6 +36,7 @@ module Superenv def determine_dynamic_linker_path path = "#{HOMEBREW_PREFIX}/lib/ld.so" return unless File.readable? path + path end end diff --git a/Library/Homebrew/extend/os/linux/hardware/cpu.rb b/Library/Homebrew/extend/os/linux/hardware/cpu.rb index 1dfca2ebe7..54127a4ff3 100644 --- a/Library/Homebrew/extend/os/linux/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/linux/hardware/cpu.rb @@ -9,6 +9,7 @@ module Hardware return :arm if arm? return :ppc if ppc? return :dunno unless intel? + # See https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers cpu_family = cpuinfo[/^cpu family\s*: ([0-9]+)/, 1].to_i cpu_model = cpuinfo[/^model\s*: ([0-9]+)/, 1].to_i diff --git a/Library/Homebrew/extend/os/linux/keg_relocate.rb b/Library/Homebrew/extend/os/linux/keg_relocate.rb index 568e707d16..a678ba3e74 100644 --- a/Library/Homebrew/extend/os/linux/keg_relocate.rb +++ b/Library/Homebrew/extend/os/linux/keg_relocate.rb @@ -45,6 +45,7 @@ class Keg end return if old_rpath == new_rpath && old_interpreter == new_interpreter + safe_system(*cmd, file) end @@ -54,6 +55,7 @@ class Keg elf_files.each do |file| next unless file.dynamic_elf? next if file.binary_executable? && skip_executables + dylibs = file.dynamically_linked_libraries results << :libcxx if dylibs.any? { |s| s.include? "libc++.so" } results << :libstdcxx if dylibs.any? { |s| s.include? "libstdc++.so" } @@ -72,6 +74,7 @@ class Keg # same dev ID and inode). This prevents relocations from being performed # on a binary more than once. next unless hardlinks.add? [pn.stat.dev, pn.stat.ino] + elf_files << pn end elf_files diff --git a/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb index 3553ada742..0f61669605 100644 --- a/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb +++ b/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb @@ -5,6 +5,7 @@ class OsxfuseRequirement < Requirement satisfy(build_env: false) do next true if libfuse_formula_exists? && Formula["libfuse"].installed? + includedirs = %w[ /usr/include /usr/local/include @@ -12,6 +13,7 @@ class OsxfuseRequirement < Requirement next true if (includedirs.map do |dir| File.exist? "#{dir}/fuse.h" end).any? + false end diff --git a/Library/Homebrew/extend/os/linux/system_config.rb b/Library/Homebrew/extend/os/linux/system_config.rb index 47eca7697e..53c42fcf32 100644 --- a/Library/Homebrew/extend/os/linux/system_config.rb +++ b/Library/Homebrew/extend/os/linux/system_config.rb @@ -18,17 +18,20 @@ class SystemConfig def host_glibc_version version = OS::Linux::Glibc.system_version return "N/A" if version.null? + version end def host_gcc_version gcc = Pathname.new "/usr/bin/gcc" return "N/A" unless gcc.executable? + `#{gcc} --version 2>/dev/null`[/ (\d+\.\d+\.\d+)/, 1] end def formula_linked_version(formula) return "N/A" unless CoreTap.instance.installed? + Formulary.factory(formula).linked_version || "N/A" rescue FormulaUnavailableError "N/A" diff --git a/Library/Homebrew/extend/os/mac/dependency_collector.rb b/Library/Homebrew/extend/os/mac/dependency_collector.rb index 543c2494ec..55b5f985eb 100644 --- a/Library/Homebrew/extend/os/mac/dependency_collector.rb +++ b/Library/Homebrew/extend/os/mac/dependency_collector.rb @@ -7,6 +7,7 @@ class DependencyCollector def git_dep_if_needed(tags) return if MacOS.version >= :lion + Dependency.new("git", tags) end @@ -14,11 +15,13 @@ class DependencyCollector def cvs_dep_if_needed(tags) return if MacOS.version < :lion + Dependency.new("cvs", tags) end def xz_dep_if_needed(tags) return if MacOS.version >= :mavericks + Dependency.new("xz", tags) end @@ -29,6 +32,7 @@ class DependencyCollector def ld64_dep_if_needed(*) # Tiger's ld is too old to properly link some software return if MacOS.version > :tiger + LD64Dependency.new end end diff --git a/Library/Homebrew/extend/os/mac/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb index 187fc03584..e76dd76279 100644 --- a/Library/Homebrew/extend/os/mac/diagnostic.rb +++ b/Library/Homebrew/extend/os/mac/diagnostic.rb @@ -352,6 +352,7 @@ module Homebrew def check_for_multiple_volumes return unless HOMEBREW_CELLAR.exist? + volumes = Volumes.new # Find the volumes for the TMP folder & HOMEBREW_CELLAR diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb index efdb03e08e..1ae63fd5d4 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/std.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/std.rb @@ -55,6 +55,7 @@ module Stdenv # Leopard's ld needs some convincing that it's building 64-bit # See: https://github.com/mistydemeo/tigerbrew/issues/59 return unless MacOS.version == :leopard && MacOS.prefer_64_bit? + append "LDFLAGS", "-arch #{Hardware::CPU.arch_64_bit}" # Many, many builds are broken thanks to Leopard's buggy ld. @@ -94,6 +95,7 @@ module Stdenv remove "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib" return unless (sdk = MacOS.sdk_path_if_needed(version)) + delete("SDKROOT") remove_from_cflags "-isysroot #{sdk}" remove "CPPFLAGS", "-isysroot #{sdk}" @@ -116,6 +118,7 @@ module Stdenv prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib" return unless (sdk = MacOS.sdk_path_if_needed(version)) + # Extra setup to support Xcode 4.3+ without CLT. self["SDKROOT"] = sdk # Tell clang/gcc where system include's are: diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index 76d8bc916d..1b1c8afc9b 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -5,6 +5,7 @@ module Superenv # @private def bin return unless DevelopmentTools.installed? + (HOMEBREW_SHIMS_PATH/"mac/super").realpath end end diff --git a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb index 5919816064..97b02c91dd 100644 --- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb +++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb @@ -29,6 +29,7 @@ module FormulaCellarChecks def check_openssl_links return unless formula.prefix.directory? + keg = Keg.new(formula.prefix) system_openssl = keg.mach_o_files.select do |obj| dlls = obj.dynamically_linked_libraries @@ -64,6 +65,7 @@ module FormulaCellarChecks def check_linkage return unless formula.prefix.directory? + keg = Keg.new(formula.prefix) CacheStoreDatabase.use(:linkage) do |db| diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb index f92134e5a4..9a50e540ba 100644 --- a/Library/Homebrew/extend/os/mac/keg_relocate.rb +++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb @@ -46,6 +46,7 @@ class Keg mach_o_files.each do |file| next if file.mach_o_executable? && skip_executables + dylibs = file.dynamically_linked_libraries results << :libcxx unless dylibs.grep(/libc\+\+.+\.dylib/).empty? results << :libstdcxx unless dylibs.grep(/libstdc\+\+.+\.dylib/).empty? @@ -122,6 +123,7 @@ class Keg def find_dylib(bad_name) return unless lib.directory? + suffix = "/#{find_dylib_suffix_from(bad_name)}" lib.find { |pn| break pn if pn.to_s.end_with?(suffix) } end @@ -135,6 +137,7 @@ class Keg # if we've already processed a file, ignore its hardlinks (which have the same dev ID and inode) # this prevents relocations from being performed on a binary more than once next unless hardlinks.add? [pn.stat.dev, pn.stat.ino] + mach_o_files << pn end diff --git a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb index bd3ff0d541..59b208d78c 100644 --- a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb @@ -24,10 +24,12 @@ class JavaRequirement < Requirement def java_home_cmd return unless File.executable?("/usr/libexec/java_home") + args = %w[--failfast] args << "--version" << @version.to_s if @version java_home = Utils.popen_read("/usr/libexec/java_home", *args).chomp return unless $CHILD_STATUS.success? + Pathname.new(java_home)/"bin/java" end diff --git a/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb index 91fec032c3..f4a5da6958 100644 --- a/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/x11_requirement.rb @@ -3,6 +3,7 @@ require "requirement" class X11Requirement < Requirement satisfy build_env: false do next false unless MacOS::XQuartz.installed? + min_version <= MacOS::XQuartz.version end diff --git a/Library/Homebrew/extend/os/mac/system_config.rb b/Library/Homebrew/extend/os/mac/system_config.rb index 721cc871a9..a44497b38a 100644 --- a/Library/Homebrew/extend/os/mac/system_config.rb +++ b/Library/Homebrew/extend/os/mac/system_config.rb @@ -8,6 +8,7 @@ class SystemConfig out, _, status = system_command("/usr/libexec/java_home", args: ["--xml", "--failfast"], print_stderr: false) return "N/A" unless status.success? + javas = [] xml = REXML::Document.new(out) REXML::XPath.each(xml, "//key[text()='JVMVersion']/following-sibling::string") do |item| diff --git a/Library/Homebrew/extend/os/mac/utils/bottles.rb b/Library/Homebrew/extend/os/mac/utils/bottles.rb index 4344adb8dc..cfc6b6c822 100644 --- a/Library/Homebrew/extend/os/mac/utils/bottles.rb +++ b/Library/Homebrew/extend/os/mac/utils/bottles.rb @@ -35,6 +35,7 @@ module Utils # :tiger_g4, :tiger_g5, etc. def find_altivec_tag(tag) return unless tag.to_s =~ /(\w+)_(g4|g4e|g5)$/ + altivec_tag = "#{Regexp.last_match(1)}_altivec".to_sym altivec_tag if key?(altivec_tag) end @@ -67,6 +68,7 @@ module Utils return false unless OS::Mac.prerelease? return true if ENV["HOMEBREW_INSTALL_OLDER_PRERELEASE_BOTTLES"] return false if ENV["HOMEBREW_NO_INSTALL_OLDER_PRERELEASE_BOTTLES"] + !ARGV.homebrew_developer? end end diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index d4820c7a3d..7362191231 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -4,12 +4,14 @@ require "metafiles" module DiskUsageExtension def disk_usage return @disk_usage if @disk_usage + compute_disk_usage @disk_usage end def file_count return @file_count if @file_count + compute_disk_usage @file_count end @@ -146,6 +148,7 @@ class Pathname # we assume this pathname object is a file obviously def write(content, *open_args) raise "Will not overwrite #{self}" if exist? + dirname.mkpath open("w", *open_args) { |f| f.write(content) } end @@ -153,6 +156,7 @@ class Pathname # Only appends to a file that is already created. def append_lines(content, *open_args) raise "Cannot append file that doesn't exist: #{self}" unless exist? + open("a", *open_args) { |f| f.puts(content) } end @@ -274,6 +278,7 @@ class Pathname def verify_checksum(expected) raise ChecksumMissingError if expected.nil? || expected.empty? + actual = Checksum.new(expected.hash_type, send(expected.hash_type).downcase) raise ChecksumMismatchError.new(self, expected, actual) unless expected == actual end @@ -364,6 +369,7 @@ class Pathname dst.mkpath Pathname.glob("#{self}/*") do |file| next if file.directory? + dst.install(file) new_file = dst.join(file.basename) file.write_env_script(new_file, env) @@ -386,11 +392,13 @@ class Pathname Pathname(from).children.each do |p| next if p.directory? next unless Metafiles.copy?(p.basename.to_s) + # Some software symlinks these files (see help2man.rb) filename = p.resolved_path # Some software links metafiles together, so by the time we iterate to one of them # we may have already moved it. libxml2's COPYING and Copyright are affected by this. next unless filename.exist? + filename.chmod 0644 install(filename) end diff --git a/Library/Homebrew/extend/string.rb b/Library/Homebrew/extend/string.rb index 7efdec917e..e7777c8281 100644 --- a/Library/Homebrew/extend/string.rb +++ b/Library/Homebrew/extend/string.rb @@ -44,6 +44,7 @@ module StringInreplaceExtension # value with "new_value", or removes the definition entirely. def change_make_var!(flag, new_value) return if gsub!(/^#{Regexp.escape(flag)}[ \t]*=[ \t]*(.*)$/, "#{flag}=#{new_value}", false) + errors << "expected to change #{flag.inspect} to #{new_value.inspect}" end diff --git a/Library/Homebrew/fetch.rb b/Library/Homebrew/fetch.rb index ca060a36c3..32f9e3f7c6 100644 --- a/Library/Homebrew/fetch.rb +++ b/Library/Homebrew/fetch.rb @@ -7,6 +7,7 @@ module Homebrew return false unless f.bottle && f.pour_bottle? return false if ARGV.build_formula_from_source?(f) return false unless f.bottle.compatible_cellar? + true end end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index e1e5262fe0..de94b29614 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -214,6 +214,7 @@ class Formula def active_spec=(spec_sym) spec = send(spec_sym) raise FormulaSpecificationError, "#{spec_sym} spec is not available for #{full_name}" unless spec + @active_spec = spec @active_spec_sym = spec_sym validate_attributes! @@ -235,6 +236,7 @@ class Formula def spec_eval(name) spec = self.class.send(name) return unless spec.url + spec.owner = self instance_variable_set("@#{name}", spec) end @@ -256,6 +258,7 @@ class Formula val = version.respond_to?(:to_str) ? version.to_str : version return unless val.nil? || val.empty? || val =~ /\s/ + raise FormulaValidationError.new(full_name, :version, val) end @@ -268,6 +271,7 @@ class Formula path = build.source["path"] if build.is_a?(Tab) return unless path =~ %r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases} return unless File.symlink?(path) + path end @@ -500,6 +504,7 @@ class Formula if options[:fetch_head] return false unless head&.downloader.is_a?(VCSDownloadStrategy) + downloader = head.downloader downloader.shutup! unless ARGV.verbose? downloader.commit_outdated?(version.version.commit) @@ -557,12 +562,14 @@ class Formula # Is formula's linked keg points to the prefix. def prefix_linked?(v = pkg_version) return false unless linked? + linked_keg.resolved_path == versioned_prefix(v) end # {PkgVersion} of the linked keg for the formula. def linked_version return unless linked? + Keg.for(linked_keg).version end @@ -1036,6 +1043,7 @@ class Formula # see gettext.rb for an example def keg_only? return false unless keg_only_reason + keg_only_reason.valid? end @@ -1052,6 +1060,7 @@ class Formula # @private def skip_clean?(path) return true if path.extname == ".la" && self.class.skip_clean_paths.include?(:la) + to_check = path.relative_path_from(prefix).to_s self.class.skip_clean_paths.include? to_check end @@ -1065,6 +1074,7 @@ class Formula def link_overwrite?(path) # Don't overwrite files not created by Homebrew. return false unless path.stat.uid == HOMEBREW_BREW_FILE.stat.uid + # Don't overwrite files belong to other keg except when that # keg's formula is deleted. begin @@ -1075,6 +1085,7 @@ class Formula tab_tap = Tab.for_keg(keg).tap # this keg doesn't below to any core/tap formula, most likely coming from a DIY install. return false if tab_tap.nil? + begin Formulary.factory(keg.name) rescue FormulaUnavailableError # rubocop:disable Lint/HandleExceptions @@ -1105,6 +1116,7 @@ class Formula # @private def patch return if patchlist.empty? + ohai "Patching" patchlist.each(&:apply) end @@ -1138,6 +1150,7 @@ class Formula return unless oldname return unless (oldname_rack = HOMEBREW_CELLAR/oldname).exist? return unless oldname_rack.resolved_path == rack + @oldname_lock = FormulaLock.new(oldname) @oldname_lock.lock end @@ -1163,6 +1176,7 @@ class Formula def outdated_kegs(options = {}) @outdated_kegs ||= Hash.new do |cache, key| raise Migrator::MigrationNeededError, self if migration_needed? + cache[key] = _outdated_kegs(key) end @outdated_kegs[options] @@ -1212,6 +1226,7 @@ class Formula def installed_alias_target_changed? target = current_installed_alias_target return false unless target + target.name != name end @@ -1237,6 +1252,7 @@ class Formula # it doesn't make sense to say that other formulae are older versions of it # because we don't know which came first. return [] if alias_path.nil? || installed_alias_target_changed? + self.class.installed_with_alias_path(alias_path).reject { |f| f.name == name } end @@ -1288,6 +1304,7 @@ class Formula # @private def <=>(other) return unless other.is_a?(Formula) + name <=> other.name end @@ -1419,6 +1436,7 @@ class Formula def self.installed_with_alias_path(alias_path) return [] if alias_path.nil? + installed.select { |f| f.installed_alias_path == alias_path } end @@ -1478,12 +1496,14 @@ class Formula # @private def tap? return false unless tap + !tap.core_tap? end # @private def print_tap_action(options = {}) return unless tap? + verb = options[:verb] || "Installing" ohai "#{verb} #{name} from #{tap}" end @@ -1532,11 +1552,13 @@ class Formula return tab_deps.map do |d| full_name = d["full_name"] next unless full_name + Dependency.new full_name end.compact end return declared_runtime_dependencies unless undeclared + declared_runtime_dependencies | undeclared_runtime_dependencies end @@ -1607,6 +1629,7 @@ class Formula %w[stable devel].each do |spec_sym| next unless spec = send(spec_sym) next unless spec.bottle_defined? + bottle_spec = spec.bottle_specification bottle_info = { "rebuild" => bottle_spec.rebuild, @@ -1747,6 +1770,7 @@ class Formula recursive_dependencies do |_, dependency| Dependency.prune if dependency.build? next if dependency.required? + if build.any_args_or_options? Dependency.prune if build.without?(dependency) elsif !dependency.recommended? @@ -1838,6 +1862,7 @@ class Formula log.puts buf # make sure dots printed with interval of at least 1 min. next unless (Time.now - last_dot) > 60 + print "." $stdout.flush last_dot = Time.now @@ -1939,6 +1964,7 @@ class Formula def mkdir(name) result = FileUtils.mkdir_p(name) return result unless block_given? + FileUtils.chdir name do yield end @@ -2259,6 +2285,7 @@ class Formula def stable(&block) @stable ||= SoftwareSpec.new return @stable unless block_given? + @stable.instance_eval(&block) end @@ -2277,6 +2304,7 @@ class Formula def devel(&block) @devel ||= SoftwareSpec.new return @devel unless block_given? + @devel.instance_eval(&block) end diff --git a/Library/Homebrew/formula_cellar_checks.rb b/Library/Homebrew/formula_cellar_checks.rb index 2902ed303b..548575e12e 100644 --- a/Library/Homebrew/formula_cellar_checks.rb +++ b/Library/Homebrew/formula_cellar_checks.rb @@ -42,6 +42,7 @@ module FormulaCellarChecks def check_jars return unless formula.lib.directory? + jars = formula.lib.children.select { |g| g.extname == ".jar" } return if jars.empty? @@ -68,6 +69,7 @@ module FormulaCellarChecks non_libraries = formula.lib.children.reject do |g| next true if g.directory? + valid_library_extension? g end return if non_libraries.empty? @@ -95,6 +97,7 @@ module FormulaCellarChecks def check_generic_executables(bin) return unless bin.directory? + generic_names = %w[run service start stop] generics = bin.children.select { |g| generic_names.include? g.basename.to_s } return if generics.empty? @@ -133,6 +136,7 @@ module FormulaCellarChecks end return unless bad_dir_name + <<~EOS Emacs Lisp files were installed into the wrong site-lisp subdirectory. They should be installed into: @@ -147,6 +151,7 @@ module FormulaCellarChecks elisps = (share/"emacs/site-lisp").children.select { |file| %w[.el .elc].include? file.extname } return if elisps.empty? + <<~EOS Emacs Lisp files were linked directly to #{HOMEBREW_PREFIX}/share/emacs/site-lisp This may cause conflicts with other packages. diff --git a/Library/Homebrew/formula_creator.rb b/Library/Homebrew/formula_creator.rb index 6a8fc91ba7..05095cb89a 100644 --- a/Library/Homebrew/formula_creator.rb +++ b/Library/Homebrew/formula_creator.rb @@ -34,6 +34,7 @@ module Homebrew def update_path return if @name.nil? || @tap.nil? + @path = Formulary.path "#{@tap}/#{@name}" end diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index f9ea6caa92..dd6f583110 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -82,6 +82,7 @@ class FormulaInstaller def build_bottle? return false unless @build_bottle + !formula.bottle_disabled? end @@ -94,6 +95,7 @@ class FormulaInstaller return false if ARGV.cc return false unless options.empty? return false if formula.bottle_disabled? + unless formula.pour_bottle? if install_bottle_options[:warn] && formula.pour_bottle_check_unsatisfied_reason opoo <<~EOS @@ -124,6 +126,7 @@ class FormulaInstaller return false unless dep.bottle && dep.pour_bottle? return false unless build.used_options.empty? return false unless dep.bottle.compatible_cellar? + true end @@ -185,6 +188,7 @@ class FormulaInstaller end return if pinned_unsatisfied_deps.empty? + raise CannotInstallFormulaError, "You must `brew unpin #{pinned_unsatisfied_deps * " "}` as installing " \ "#{formula.full_name} requires the latest version of pinned dependencies" @@ -293,10 +297,12 @@ class FormulaInstaller formula.rack.rmdir_if_possible end raise if ARGV.homebrew_developer? || e.is_a?(Interrupt) + @pour_failed = true onoe e.message opoo "Bottle installation failed: building from source." raise BuildToolsError, [formula] unless DevelopmentTools.installed? + compute_and_install_dependencies unless ignore_deps? else @poured_bottle = true @@ -401,6 +407,7 @@ class FormulaInstaller req_map.each_pair do |dependent, reqs| reqs.each do |req| next if dependent.installed? && req.name == "maximummacos" + @requirement_messages << "#{dependent}: #{req.message}" fatals << req if req.fatal? end @@ -512,6 +519,7 @@ class FormulaInstaller end options += effective_build_options_for(formula).used_options.to_a return if options.empty? + options.join(" ") end @@ -589,6 +597,7 @@ class FormulaInstaller caveats = Caveats.new(formula) return if caveats.empty? + @show_summary_heading = true ohai "Caveats", caveats.to_s Homebrew.messages.record_caveats(formula, caveats) @@ -618,6 +627,7 @@ class FormulaInstaller # Updates the cache for a particular formula after doing an install CacheStoreDatabase.use(:linkage) do |db| break unless db.created? + LinkageChecker.new(keg, formula, cache_db: db, rebuild_cache: true) end @@ -826,6 +836,7 @@ class FormulaInstaller end return if link_overwrite_backup.empty? + opoo "These files were overwritten during `brew link` step:" puts link_overwrite_backup.keys puts @@ -835,6 +846,7 @@ class FormulaInstaller def install_plist return unless formula.plist + formula.plist_path.atomic_write(formula.plist) formula.plist_path.chmod 0644 log = formula.var/"log" @@ -947,6 +959,7 @@ class FormulaInstaller def problem_if_output(output) return unless output + opoo output @show_summary_heading = true end @@ -969,6 +982,7 @@ class FormulaInstaller def lock return unless self.class.locked.empty? + unless ignore_deps? formula.recursive_dependencies.each do |dep| self.class.locked << dep.to_formula @@ -982,6 +996,7 @@ class FormulaInstaller def unlock return unless hold_locks? + self.class.locked.each(&:unlock) self.class.locked.clear @hold_locks = false @@ -990,6 +1005,7 @@ class FormulaInstaller def puts_requirement_messages return unless @requirement_messages return if @requirement_messages.empty? + $stderr.puts @requirement_messages end end diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb index aef1a58ba5..fcdd45630f 100644 --- a/Library/Homebrew/formula_support.rb +++ b/Library/Homebrew/formula_support.rb @@ -58,6 +58,7 @@ class BottleDisableReason def to_s return "This formula doesn't require compiling." if unneeded? + @reason end end diff --git a/Library/Homebrew/formula_versions.rb b/Library/Homebrew/formula_versions.rb index 67edba9c5e..3de594eaaa 100644 --- a/Library/Homebrew/formula_versions.rb +++ b/Library/Homebrew/formula_versions.rb @@ -71,6 +71,7 @@ class FormulaVersions formula_at_revision(rev) do |f| [:stable, :devel].each do |spec_sym| next unless spec = f.send(spec_sym) + map[spec_sym] ||= { version: spec.version, checksum: spec.checksum } end end @@ -120,6 +121,7 @@ class FormulaVersions map[:stable][f.stable.version] << f.send(attribute) end return unless f.devel + map[:devel][f.devel.version] ||= [] map[:devel][f.devel.version] << f.send(attribute) end diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 8c8d47a97a..044f8e242e 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -124,6 +124,7 @@ module Formulary def load_file $stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if ARGV.debug? raise FormulaUnavailableError, name unless path.file? + Formulary.load_formula_from_path(name, path) end end @@ -304,6 +305,7 @@ module Formulary # * a local bottle reference def self.factory(ref, spec = :stable, alias_path: nil, from: nil) raise ArgumentError, "Formulae must have a ref!" unless ref + loader_for(ref, from: from).get_formula(spec, alias_path: alias_path) end diff --git a/Library/Homebrew/hardware.rb b/Library/Homebrew/hardware.rb index e59577da3c..a90ec46a3d 100644 --- a/Library/Homebrew/hardware.rb +++ b/Library/Homebrew/hardware.rb @@ -72,6 +72,7 @@ module Hardware def cores return @cores if @cores + @cores = Utils.popen_read("getconf", "_NPROCESSORS_ONLN").chomp.to_i @cores = 1 unless $CHILD_STATUS.success? @cores diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb index ddb66060f9..b2c9f8dde6 100644 --- a/Library/Homebrew/install.rb +++ b/Library/Homebrew/install.rb @@ -43,6 +43,7 @@ module Homebrew @checks.public_send(type).each do |check| out = @checks.public_send(check) next if out.nil? + failed ||= true ofail out end diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index ea2c334373..8e369fe53c 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -174,6 +174,7 @@ class Keg path = path.realpath until path.root? return Keg.new(path) if path.parent.parent == HOMEBREW_CELLAR.realpath + path = path.parent.realpath # realpath() prevents root? failing end raise NotAKegError, "#{path} is not inside a keg" @@ -196,6 +197,7 @@ class Keg path = path.resolved_path if path.to_s.start_with?("#{HOMEBREW_PREFIX}/opt/") raise "#{path} is not a valid keg" unless path.parent.parent.realpath == HOMEBREW_CELLAR.realpath raise "#{path} is not a directory" unless path.directory? + @path = path @name = path.parent.basename.to_s @linked_keg_record = HOMEBREW_LINKED_KEGS/name @@ -221,9 +223,11 @@ class Keg def empty_installation? Pathname.glob("#{path}/*") do |file| return false if file.directory? && !file.children.reject(&:ds_store?).empty? + basename = file.basename.to_s next if Metafiles.copy?(basename) next if %w[.DS_Store INSTALL_RECEIPT.json].include?(basename) + return false end @@ -270,6 +274,7 @@ class Keg 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 @@ -299,6 +304,7 @@ class Keg def uninstall CacheStoreDatabase.use(:linkage) do |db| break unless db.created? + LinkageCacheStore.new(path, db).flush_cache! end @@ -316,6 +322,7 @@ class Keg KEG_LINK_DIRECTORIES.map { |d| path/d }.each do |dir| next unless dir.exist? + dir.find do |src| dst = HOMEBREW_PREFIX + src.relative_path_from(path) dst.extend(ObserverPathnameExtension) @@ -324,6 +331,7 @@ class Keg # check whether the file to be unlinked is from the current keg first next unless dst.symlink? && src == dst.resolved_path + if mode.dry_run puts dst Find.prune if src.directory? @@ -398,6 +406,7 @@ class Keg def elisp_installed? return false unless (path/"share/emacs/site-lisp"/name).exist? + (path/"share/emacs/site-lisp"/name).children.any? { |f| %w[.el .elc].include? f.extname } end @@ -499,6 +508,7 @@ class Keg def remove_oldname_opt_record return unless oldname_opt_record return unless oldname_opt_record.resolved_path == path + @oldname_opt_record.unlink @oldname_opt_record.parent.rmdir_if_possible @oldname_opt_record = nil @@ -526,6 +536,7 @@ class Keg end return unless oldname_opt_record + oldname_opt_record.delete make_relative_symlink(oldname_opt_record, path, mode) end @@ -555,6 +566,7 @@ class Keg end return unless stat.directory? + begin keg = Keg.for(src) rescue NotAKegError @@ -595,6 +607,7 @@ class Keg dst.make_relative_symlink(src) rescue Errno::EEXIST => e raise ConflictError.new(self, src.relative_path_from(path), dst, e) if dst.exist? + if dst.symlink? dst.unlink retry @@ -611,8 +624,10 @@ class Keg def link_dir(relative_dir, mode) root = path/relative_dir return unless root.exist? + root.find do |src| next if src == root + dst = HOMEBREW_PREFIX + src.relative_path_from(path) dst.extend ObserverPathnameExtension @@ -631,6 +646,7 @@ class Keg Find.prune when :info next if File.basename(src) == "dir" # skip historical local 'dir' files + make_relative_symlink dst, src, mode dst.install_info else @@ -639,6 +655,7 @@ class Keg elsif src.directory? # if the dst dir already exists, then great! walk the rest of the tree tho next if dst.directory? && !dst.symlink? + # no need to put .app bundles in the path, the user can just use # spotlight, or the open command and actual mac apps use an equivalent Find.prune if src.extname == ".app" diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index d890cde30a..6320a61bda 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -16,9 +16,11 @@ class Keg link = file.readlink # Don't fix relative symlinks next unless link.absolute? + link_starts_cellar = link.to_s.start_with?(HOMEBREW_CELLAR.to_s) link_starts_prefix = link.to_s.start_with?(HOMEBREW_PREFIX.to_s) next if !link_starts_cellar && !link_starts_prefix + new_src = link.relative_path_from(file.parent) file.unlink FileUtils.ln_s(new_src, file) @@ -70,6 +72,7 @@ class Keg } 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) } begin @@ -102,6 +105,7 @@ class Keg until io.eof? file = Pathname.new(io.readline.chomp) next if file.symlink? + yield file if hardlinks.add? file.stat.ino end end @@ -126,6 +130,7 @@ class Keg next false if pn.basename.to_s == "orig-prefix.txt" # for python virtualenvs next true if pn == self/".brew/#{name}.rb" next true if Metafiles::EXTENSIONS.include?(pn.extname) + if pn.text_executable? text_files << pn next true @@ -144,8 +149,10 @@ class Keg # will be `nil` for those lines next unless info next unless info.include?("text") + path = Pathname.new(path) next unless files.include?(path) + text_files << path end end @@ -158,6 +165,7 @@ class Keg path.find do |pn| next if pn.symlink? || pn.directory? || ![".la", ".lai"].include?(pn.extname) + libtool_files << pn end libtool_files diff --git a/Library/Homebrew/language/node.rb b/Library/Homebrew/language/node.rb index ce9baea21e..e7958e7d95 100644 --- a/Library/Homebrew/language/node.rb +++ b/Library/Homebrew/language/node.rb @@ -14,12 +14,14 @@ module Language if !$CHILD_STATUS.exitstatus.zero? || output.lines.empty? raise "npm failed to pack #{Dir.pwd}" end + output.lines.last.chomp end def self.setup_npm_environment # guard that this is only run once return if @env_set + @env_set = true # explicitly use our npm and node-gyp executables instead of the user # managed ones in HOMEBREW_PREFIX/lib/node_modules which might be broken diff --git a/Library/Homebrew/language/python.rb b/Library/Homebrew/language/python.rb index e96fd5ee8e..3f840e72db 100644 --- a/Library/Homebrew/language/python.rb +++ b/Library/Homebrew/language/python.rb @@ -5,6 +5,7 @@ module Language def self.major_minor_version(python) version = /\d\.\d/.match `#{python} --version 2>&1` return unless version + Version.create(version.to_s) end @@ -17,6 +18,7 @@ module Language { "python@3" => "python3", "python@2" => "python2.7" }.each do |python_formula, python| python_formula = Formulary.factory(python_formula) next if build.without? python_formula.to_s + version = major_minor_version python ENV["PYTHONPATH"] = if python_formula.installed? nil @@ -32,6 +34,7 @@ module Language version = major_minor_version python return unless homebrew_site_packages(version).directory? return unless homebrew_site_packages(version).writable_real? + probe_file = homebrew_site_packages(version)/"homebrew-pth-probe.pth" begin probe_file.atomic_write("import site; site.homebrew_was_here = True") @@ -101,8 +104,10 @@ module Language xy = Language::Python.major_minor_version python pth_contents = formula_deps.map do |d| next if d.build? + dep_site_packages = Formula[d.name].opt_lib/"python#{xy}/site-packages" next unless dep_site_packages.exist? + "import site; site.addsitedir('#{dep_site_packages}')\n" end.compact unless pth_contents.empty? @@ -121,6 +126,7 @@ module Language # @api private def needs_python?(python) return true if build.with?(python) + (requirements.to_a | deps).any? { |r| r.name == python && r.required? } end @@ -136,6 +142,7 @@ module Language if python.nil? wanted = %w[python python@2 python2 python3 python@3].select { |py| needs_python?(py) } raise FormulaAmbiguousPythonError, self if wanted.size > 1 + python = wanted.first || "python2.7" python = "python3" if python == "python" end @@ -184,6 +191,7 @@ module Language @venv_root.find do |f| next unless f.symlink? next unless (rp = f.realpath.to_s).start_with? HOMEBREW_CELLAR + python = rp.include?("python@2") ? "python@2" : "python" new_target = rp.sub %r{#{HOMEBREW_CELLAR}/#{python}/[^/]+}, Formula[python].opt_prefix f.unlink @@ -212,6 +220,7 @@ module Language targets.each do |t| if t.respond_to? :stage next if t.name == "homebrew-virtualenv" + t.stage { do_install Pathname.pwd } else t = t.lines.map(&:strip) if t.respond_to?(:lines) && t =~ /\n/ diff --git a/Library/Homebrew/lazy_object.rb b/Library/Homebrew/lazy_object.rb index add5a339d8..520ae643db 100644 --- a/Library/Homebrew/lazy_object.rb +++ b/Library/Homebrew/lazy_object.rb @@ -5,6 +5,7 @@ class LazyObject < Delegator def __getobj__ return @__delegate__ if defined?(@__delegate__) + @__delegate__ = @__callable__.call end diff --git a/Library/Homebrew/linkage_cache_store.rb b/Library/Homebrew/linkage_cache_store.rb index f17fbad18e..ad50ae7b41 100644 --- a/Library/Homebrew/linkage_cache_store.rb +++ b/Library/Homebrew/linkage_cache_store.rb @@ -67,6 +67,7 @@ class LinkageCacheStore < CacheStore def fetch_hash_values(type) keg_cache = database.get(@keg_path) return {} unless keg_cache + json_string_to_ruby_hash(keg_cache)[type.to_s] end end diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 697b22ae9e..e3bc950bd2 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -39,6 +39,7 @@ class LinkageChecker def display_reverse_output return if @reverse_links.empty? + sorted = @reverse_links.sort sorted.each do |dylib, files| puts dylib @@ -90,6 +91,7 @@ class LinkageChecker @keg.find do |file| next if file.symlink? || file.directory? next if !file.dylib? && !file.binary_executable? && !file.mach_o_bundle? + # weakly loaded dylibs may not actually exist on disk, so skip them # when checking for broken linkage keg_files_dylibs[file] = @@ -104,6 +106,7 @@ class LinkageChecker @reverse_links[dylib] << file next if checked_dylibs.include? dylib + checked_dylibs << dylib if dylib.start_with? "@" @@ -117,6 +120,7 @@ class LinkageChecker @system_dylibs << dylib rescue Errno::ENOENT next if harmless_broken_link?(dylib) + if (dep = dylib_to_dep(dylib)) @broken_deps[dep] |= [dylib] else @@ -149,6 +153,7 @@ class LinkageChecker filter_out = proc do |dep| next true if dep.build? next false unless dep.optional? || dep.recommended? + formula.build.without?(dep) end @@ -166,6 +171,7 @@ class LinkageChecker @brewed_dylibs.each_key do |full_name| name = full_name.split("/").last next if name == formula.name + if recursive_deps.include?(name) indirect_deps << full_name unless declared_deps_names.include?(name) else @@ -178,6 +184,7 @@ class LinkageChecker unnecessary_deps = declared_deps_full_names.reject do |full_name| next true if Formula[full_name].bin.directory? + name = full_name.split("/").last @brewed_dylibs.keys.map { |l| l.split("/").last }.include?(name) end @@ -193,6 +200,7 @@ class LinkageChecker version_hash[unversioned_name] ||= Set.new version_hash[unversioned_name] << name next if version_hash[unversioned_name].length < 2 + version_conflict_deps += version_hash[unversioned_name] end @@ -227,6 +235,7 @@ class LinkageChecker # Things may either be an array, or a hash of (label -> array) def display_items(label, things, puts_output: true) return if things.empty? + output = "#{label}:" if things.is_a? Hash things.keys.sort.each do |list_label| diff --git a/Library/Homebrew/locale.rb b/Library/Homebrew/locale.rb index 44179ada0f..8b194d568f 100644 --- a/Library/Homebrew/locale.rb +++ b/Library/Homebrew/locale.rb @@ -42,6 +42,7 @@ class Locale regex = self.class.const_get("#{key.upcase}_REGEX") raise ParserError, "'#{value}' does not match #{regex}" unless value =~ regex + instance_variable_set(:"@#{key}", value) end end diff --git a/Library/Homebrew/lock_file.rb b/Library/Homebrew/lock_file.rb index 6265e32f94..c694c62220 100644 --- a/Library/Homebrew/lock_file.rb +++ b/Library/Homebrew/lock_file.rb @@ -13,11 +13,13 @@ class LockFile @path.parent.mkpath create_lockfile return if @lockfile.flock(File::LOCK_EX | File::LOCK_NB) + raise OperationInProgressError, @name end def unlock return if @lockfile.nil? || @lockfile.closed? + @lockfile.flock(File::LOCK_UN) @lockfile.close end @@ -33,6 +35,7 @@ class LockFile def create_lockfile return unless @lockfile.nil? || @lockfile.closed? + @lockfile = @path.open(File::RDWR | File::CREAT) @lockfile.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) end diff --git a/Library/Homebrew/messages.rb b/Library/Homebrew/messages.rb index f76167e7a3..5ee9901ded 100644 --- a/Library/Homebrew/messages.rb +++ b/Library/Homebrew/messages.rb @@ -26,6 +26,7 @@ class Messages def display_caveats return if @formula_count <= 1 return if @caveats.empty? + oh1 "Caveats" @caveats.each do |c| ohai c[:formula], c[:caveats] @@ -34,6 +35,7 @@ class Messages def display_install_times return if install_times.empty? + oh1 "Installation times" install_times.each do |t| puts format("%-20s %10.3f s", t[:formula], t[:time]) diff --git a/Library/Homebrew/metafiles.rb b/Library/Homebrew/metafiles.rb index 7f0f59dca1..4a790850bf 100644 --- a/Library/Homebrew/metafiles.rb +++ b/Library/Homebrew/metafiles.rb @@ -13,6 +13,7 @@ module Metafiles def list?(file) return false if %w[.DS_Store INSTALL_RECEIPT.json].include?(file) + !copy?(file) end diff --git a/Library/Homebrew/migrator.rb b/Library/Homebrew/migrator.rb index 52f15bc339..cb3745c5d6 100644 --- a/Library/Homebrew/migrator.rb +++ b/Library/Homebrew/migrator.rb @@ -87,14 +87,17 @@ class Migrator def self.needs_migration?(formula) oldname = formula.oldname return false unless oldname + oldname_rack = HOMEBREW_CELLAR/oldname return false if oldname_rack.symlink? return false unless oldname_rack.directory? + true end def self.migrate_if_needed(formula) return unless Migrator.needs_migration?(formula) + begin migrator = Migrator.new(formula) migrator.migrate @@ -193,6 +196,7 @@ class Migrator link_newname unless old_linked_keg.nil? update_tabs return unless formula.outdated? + opoo <<~EOS #{Formatter.identifier(newname)} is outdated! To avoid broken installations, as soon as possible please run: @@ -220,6 +224,7 @@ class Migrator conflicted = false old_cellar.each_child do |c| next unless (new_cellar/c.basename).exist? + begin FileUtils.rm_rf c rescue Errno::EACCES @@ -243,6 +248,7 @@ class Migrator def repin return unless pinned? + # old_pin_record is a relative symlink and when we try to to read it # from we actually try to find file # /../<...>/../Cellar/name/version. @@ -323,6 +329,7 @@ class Migrator # Link keg to opt if it was linked before migrating. def link_oldname_opt return unless old_opt_record + old_opt_record.delete if old_opt_record.symlink? old_opt_record.make_relative_symlink(new_linked_keg_record) end @@ -340,6 +347,7 @@ class Migrator # Remove opt/oldname link if it belongs to newname. def unlink_oldname_opt return unless old_opt_record + if old_opt_record.symlink? && old_opt_record.exist? \ && new_linked_keg_record.exist? \ && new_linked_keg_record.realpath == old_opt_record.realpath @@ -384,6 +392,7 @@ class Migrator end return if old_linked_keg.nil? + # The keg used to be linked and when we backup everything we restore # Cellar/oldname, the target also gets restored, so we are able to # create a keg using its old path diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb index 5d0e58b3f2..4cf229b125 100644 --- a/Library/Homebrew/missing_formula.rb +++ b/Library/Homebrew/missing_formula.rb @@ -120,8 +120,10 @@ module Homebrew def deleted_reason(name, silent: false) path = Formulary.path name return if File.exist? path + tap = Tap.from_path(path) return if tap.nil? || !File.exist?(tap.path) + relative_path = path.relative_path_from tap.path tap.path.cd do diff --git a/Library/Homebrew/options.rb b/Library/Homebrew/options.rb index ddaa9d2645..fa043c4a94 100644 --- a/Library/Homebrew/options.rb +++ b/Library/Homebrew/options.rb @@ -13,6 +13,7 @@ class Option def <=>(other) return unless other.is_a?(Option) + name <=> other.name end diff --git a/Library/Homebrew/os.rb b/Library/Homebrew/os.rb index ed12ea734f..24796f0a1e 100644 --- a/Library/Homebrew/os.rb +++ b/Library/Homebrew/os.rb @@ -1,11 +1,13 @@ module OS def self.mac? return false if ENV["HOMEBREW_TEST_GENERIC_OS"] + RbConfig::CONFIG["host_os"].include? "darwin" end def self.linux? return false if ENV["HOMEBREW_TEST_GENERIC_OS"] + RbConfig::CONFIG["host_os"].include? "linux" end diff --git a/Library/Homebrew/os/linux/elf.rb b/Library/Homebrew/os/linux/elf.rb index 3865ef644c..26dc0c659b 100644 --- a/Library/Homebrew/os/linux/elf.rb +++ b/Library/Homebrew/os/linux/elf.rb @@ -94,10 +94,12 @@ module ELFShim ldd_paths = ldd_output.map do |line| match = line.match(/\t.+ => (.+) \(.+\)|\t(.+) => not found/) next unless match + match.captures.compact.first end.compact @dylibs = ldd_paths.select do |ldd_path| next true unless ldd_path.start_with? "/" + needed.include? File.basename(ldd_path) end end @@ -133,6 +135,7 @@ module ELFShim lines.each do |s| filename = s[/\[(.*)\]/, 1] next if filename.nil? + if s.include? "(SONAME)" soname = filename elsif s.include? "(NEEDED)" diff --git a/Library/Homebrew/os/linux/glibc.rb b/Library/Homebrew/os/linux/glibc.rb index 710946bbc1..7be42f2043 100644 --- a/Library/Homebrew/os/linux/glibc.rb +++ b/Library/Homebrew/os/linux/glibc.rb @@ -5,8 +5,10 @@ module OS def system_version return @system_version if @system_version + version = Utils.popen_read("/usr/bin/ldd", "--version")[/ (\d+\.\d+)/, 1] return Version::NULL unless version + @system_version = Version.new version end end diff --git a/Library/Homebrew/os/mac/keg.rb b/Library/Homebrew/os/mac/keg.rb index 6f2d65fb42..631a699168 100644 --- a/Library/Homebrew/os/mac/keg.rb +++ b/Library/Homebrew/os/mac/keg.rb @@ -1,6 +1,7 @@ class Keg def change_dylib_id(id, file) return if file.dylib_id == id + @require_relocation = true puts "Changing dylib ID of #{file}\n from #{file.dylib_id}\n to #{id}" if ARGV.debug? MachO::Tools.change_dylib_id(file, id, strict: false) @@ -15,6 +16,7 @@ class Keg def change_install_name(old, new, file) return if old == new + @require_relocation = true puts "Changing install name in #{file}\n from #{old}\n to #{new}" if ARGV.debug? MachO::Tools.change_install_name(file, old, new, strict: false) diff --git a/Library/Homebrew/os/mac/mach.rb b/Library/Homebrew/os/mac/mach.rb index 0ab7a0d3a7..49e49cd702 100644 --- a/Library/Homebrew/os/mac/mach.rb +++ b/Library/Homebrew/os/mac/mach.rb @@ -45,6 +45,7 @@ module MachOShim # ... but complain about other (parse) errors for further investigation. onoe "Failed to read Mach-O binary: #{self}" raise if ARGV.homebrew_developer? + [] end end diff --git a/Library/Homebrew/os/mac/sdk.rb b/Library/Homebrew/os/mac/sdk.rb index 1a167b97e4..63b20cd7c7 100644 --- a/Library/Homebrew/os/mac/sdk.rb +++ b/Library/Homebrew/os/mac/sdk.rb @@ -40,6 +40,7 @@ module OS end # Only return an SDK older than the OS version if it was specifically requested return unless v || (!sdk.nil? && sdk.version >= OS::Mac.version) + sdk end diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index 8f235cbc61..85dcb78861 100644 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -39,6 +39,7 @@ module OS def below_minimum_version? return false unless installed? + version < minimum_version end @@ -48,11 +49,13 @@ module OS def needs_clt_installed? return false if latest_sdk_version? + without_clt? end def outdated? return false unless installed? + version < latest_version end @@ -79,6 +82,7 @@ module OS def toolchain_path return if version < "4.3" + Pathname.new("#{prefix}/Toolchains/XcodeDefault.xctoolchain") end @@ -140,6 +144,7 @@ module OS #{which("xcodebuild")} ].uniq.each do |xcodebuild_path| next unless File.executable? xcodebuild_path + xcodebuild_output = Utils.popen_read(xcodebuild_path, "-version") next unless $CHILD_STATUS.success? @@ -158,6 +163,7 @@ module OS def detect_version_from_clang_version return "dunno" if DevelopmentTools.clang_version.null? + # This logic provides a fake Xcode version based on the # installed CLT version. This is useful as they are packaged # simultaneously so workarounds need to apply to both based on their @@ -290,12 +296,14 @@ module OS # Lion was the first version of OS X to ship with a CLT return false if MacOS.version < :lion return false unless installed? + version < minimum_version end def outdated? clang_version = detect_clang_version return false unless clang_version + ::Version.new(clang_version) < latest_version end @@ -332,6 +340,7 @@ module OS else @header_version ||= MacOS.pkgutil_info(HEADER_PKG_ID)[/version: (.+)$/, 1] return ::Version::NULL unless @header_version + ::Version.new(@header_version) end end diff --git a/Library/Homebrew/os/mac/xquartz.rb b/Library/Homebrew/os/mac/xquartz.rb index 9148e178b0..a23701006f 100644 --- a/Library/Homebrew/os/mac/xquartz.rb +++ b/Library/Homebrew/os/mac/xquartz.rb @@ -134,6 +134,7 @@ module OS def outdated? return false unless installed? return false if provided_by_apple? + version < latest_version end diff --git a/Library/Homebrew/patch.rb b/Library/Homebrew/patch.rb index 9d07e21c35..a77e8b8eb2 100644 --- a/Library/Homebrew/patch.rb +++ b/Library/Homebrew/patch.rb @@ -144,6 +144,7 @@ class ExternalPatch the "apply" method was used one or more times in the patch-do block. EOS end + patch_files << children.first.basename end dir.cd do diff --git a/Library/Homebrew/pkg_version.rb b/Library/Homebrew/pkg_version.rb index b68d78cf8e..f138f764ce 100644 --- a/Library/Homebrew/pkg_version.rb +++ b/Library/Homebrew/pkg_version.rb @@ -33,6 +33,7 @@ class PkgVersion def <=>(other) return unless other.is_a?(PkgVersion) + (version <=> other.version).nonzero? || revision <=> other.revision end alias eql? == diff --git a/Library/Homebrew/requirement.rb b/Library/Homebrew/requirement.rb index 608e8d3a35..8dcd865498 100644 --- a/Library/Homebrew/requirement.rb +++ b/Library/Homebrew/requirement.rb @@ -16,6 +16,7 @@ class Requirement @download ||= self.class.download tags.each do |tag| next unless tag.is_a? Hash + @cask ||= tag[:cask] @download ||= tag[:download] end @@ -53,8 +54,10 @@ class Requirement def satisfied? satisfy = self.class.satisfy return true unless satisfy + @satisfied_result = satisfy.yielder { |p| instance_eval(&p) } return false unless @satisfied_result + true end @@ -66,6 +69,7 @@ class Requirement def satisfied_result_parent return unless @satisfied_result.is_a?(Pathname) + parent = @satisfied_result.resolved_path.parent if parent.to_s =~ %r{^#{Regexp.escape(HOMEBREW_CELLAR)}/([\w+-.@]+)/[^/]+/(s?bin)/?$} parent = HOMEBREW_PREFIX/"opt/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}" @@ -88,6 +92,7 @@ class Requirement return unless parent return if ["#{HOMEBREW_PREFIX}/bin", "#{HOMEBREW_PREFIX}/bin"].include?(parent.to_s) return if PATH.new(ENV["PATH"]).include?(parent.to_s) + ENV.prepend_path("PATH", parent) end @@ -151,6 +156,7 @@ class Requirement def satisfy(options = nil, &block) return @satisfied if options.nil? && !block_given? + options = {} if options.nil? @satisfied = Requirement::Satisfier.new(options, &block) end @@ -203,6 +209,7 @@ class Requirement formulae.each do |f| f.requirements.each do |req| next if prune?(f, req, &block) + reqs << req end end diff --git a/Library/Homebrew/requirements/java_requirement.rb b/Library/Homebrew/requirements/java_requirement.rb index 726ecc3f95..35e23d5e19 100644 --- a/Library/Homebrew/requirements/java_requirement.rb +++ b/Library/Homebrew/requirements/java_requirement.rb @@ -21,6 +21,7 @@ class JavaRequirement < Requirement satisfy build_env: false do setup_java next false unless @java + next true end @@ -76,6 +77,7 @@ class JavaRequirement < Requirement def setup_java java = preferred_java return unless java + @java = java @java_home = java.parent.parent end @@ -103,6 +105,7 @@ class JavaRequirement < Requirement def env_java_common return unless @java_home + java_home = Pathname.new(@java_home) ENV["JAVA_HOME"] = java_home ENV.prepend_path "PATH", java_home/"bin" @@ -110,8 +113,10 @@ class JavaRequirement < Requirement def env_oracle_jdk return unless @java_home + java_home = Pathname.new(@java_home) return unless (java_home/"include").exist? + ENV.append_to_cflags "-I#{java_home}/include" ENV.append_to_cflags "-I#{java_home}/include/#{oracle_java_os}" true @@ -124,6 +129,7 @@ class JavaRequirement < Requirement def satisfies_version(java) java_version_s = system_command(java, args: ["-version"], print_stderr: false).stderr[/\d+.\d/] return false unless java_version_s + java_version = Version.create(java_version_s) needed_version = Version.create(version_without_plus) if exact_version? diff --git a/Library/Homebrew/requirements/macos_requirement.rb b/Library/Homebrew/requirements/macos_requirement.rb index c89144d2c2..37c53cf108 100644 --- a/Library/Homebrew/requirements/macos_requirement.rb +++ b/Library/Homebrew/requirements/macos_requirement.rb @@ -16,16 +16,19 @@ class MacOSRequirement < Requirement next MacOS.version >= @version if minimum_version_specified? next true if OS.mac? next true if @version + false end def message return "macOS is required." unless minimum_version_specified? + "macOS #{@version.pretty_name} or newer is required." end def display_s return "macOS is required" unless minimum_version_specified? + "macOS >= #{@version}" end end diff --git a/Library/Homebrew/requirements/x11_requirement.rb b/Library/Homebrew/requirements/x11_requirement.rb index c2ab2944c9..b7de5a2848 100644 --- a/Library/Homebrew/requirements/x11_requirement.rb +++ b/Library/Homebrew/requirements/x11_requirement.rb @@ -46,6 +46,7 @@ class X11Requirement < Requirement def <=>(other) return unless other.is_a? X11Requirement + 0 end diff --git a/Library/Homebrew/requirements/xcode_requirement.rb b/Library/Homebrew/requirements/xcode_requirement.rb index 6cb7d45d73..ac6744e2a5 100644 --- a/Library/Homebrew/requirements/xcode_requirement.rb +++ b/Library/Homebrew/requirements/xcode_requirement.rb @@ -13,6 +13,7 @@ class XcodeRequirement < Requirement def xcode_installed_version return false unless MacOS::Xcode.installed? return true unless @version + MacOS::Xcode.version >= @version end diff --git a/Library/Homebrew/resource.rb b/Library/Homebrew/resource.rb index a4989ed058..45fb18ad9b 100644 --- a/Library/Homebrew/resource.rb +++ b/Library/Homebrew/resource.rb @@ -49,6 +49,7 @@ class Resource def download_name return owner.name if name.nil? return escaped_name if owner.nil? + "#{owner.name}--#{escaped_name}" end @@ -84,6 +85,7 @@ class Resource def apply_patches return if patches.empty? + ohai "Patching #{name}" patches.each(&:apply) end @@ -141,6 +143,7 @@ class Resource def url(val = nil, **specs) return @url if val.nil? + @url = val @specs.merge!(specs) @using = @specs.delete(:using) diff --git a/Library/Homebrew/rubocops/caveats_cop.rb b/Library/Homebrew/rubocops/caveats_cop.rb index 7ce22f22aa..c64a9c78ab 100644 --- a/Library/Homebrew/rubocops/caveats_cop.rb +++ b/Library/Homebrew/rubocops/caveats_cop.rb @@ -7,6 +7,7 @@ module RuboCop def audit_formula(_node, _class_node, _parent_class_node, _body_node) caveats_strings.each do |n| next unless regex_match_group(n, /\bsetuid\b/i) + problem "Don't recommend setuid in the caveats, suggest sudo instead." end end diff --git a/Library/Homebrew/rubocops/checksum_cop.rb b/Library/Homebrew/rubocops/checksum_cop.rb index 6eee16f2bf..7b42de4179 100644 --- a/Library/Homebrew/rubocops/checksum_cop.rb +++ b/Library/Homebrew/rubocops/checksum_cop.rb @@ -6,6 +6,7 @@ module RuboCop class Checksum < FormulaCop def audit_formula(_node, _class_node, _parent_class_node, body_node) return if body_node.nil? + if method_called_ever?(body_node, :md5) problem "MD5 checksums are deprecated, please use SHA256" end @@ -23,6 +24,7 @@ module RuboCop def audit_sha256(checksum) return if checksum.nil? + if regex_match_group(checksum, /^$/) @offense_source_range = @offensive_node.source_range problem "sha256 is empty" @@ -34,6 +36,7 @@ module RuboCop end return unless regex_match_group(checksum, /[^a-f0-9]+/i) + problem "sha256 contains invalid characters" end end @@ -41,11 +44,13 @@ module RuboCop class ChecksumCase < FormulaCop def audit_formula(_node, _class_node, _parent_class_node, body_node) return if body_node.nil? + sha256_calls = find_every_method_call_by_name(body_node, :sha256) sha256_calls.each do |sha256_call| checksum = get_checksum_node(sha256_call) next if checksum.nil? next unless regex_match_group(checksum, /[A-F]+/) + problem "sha256 should be lowercase" end end diff --git a/Library/Homebrew/rubocops/class_cop.rb b/Library/Homebrew/rubocops/class_cop.rb index 1a41b7b252..f6586e0054 100644 --- a/Library/Homebrew/rubocops/class_cop.rb +++ b/Library/Homebrew/rubocops/class_cop.rb @@ -13,6 +13,7 @@ module RuboCop def audit_formula(_node, _class_node, parent_class_node, _body_node) parent_class = class_name(parent_class_node) return unless DEPRECATED_CLASSES.include?(parent_class) + problem "#{parent_class} is deprecated, use Formula instead" end @@ -84,6 +85,7 @@ module RuboCop return unless test.body.single_line? && test.body.source.to_s == "true" + problem "`test do` should contain a real test" end end diff --git a/Library/Homebrew/rubocops/components_order_cop.rb b/Library/Homebrew/rubocops/components_order_cop.rb index 385d368375..170e397644 100644 --- a/Library/Homebrew/rubocops/components_order_cop.rb +++ b/Library/Homebrew/rubocops/components_order_cop.rb @@ -55,8 +55,10 @@ module RuboCop # Check if each present_components is above rest of the present_components @present_components.take(@present_components.size - 1).each_with_index do |preceding_component, p_idx| next if preceding_component.empty? + @present_components.drop(p_idx + 1).each do |succeeding_component| next if succeeding_component.empty? + @offensive_nodes = check_precedence(preceding_component, succeeding_component) component_problem @offensive_nodes[0], @offensive_nodes[1] if @offensive_nodes end @@ -71,6 +73,7 @@ module RuboCop # 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)})" diff --git a/Library/Homebrew/rubocops/components_redundancy_cop.rb b/Library/Homebrew/rubocops/components_redundancy_cop.rb index 553800337f..a0fe004a89 100644 --- a/Library/Homebrew/rubocops/components_redundancy_cop.rb +++ b/Library/Homebrew/rubocops/components_redundancy_cop.rb @@ -32,6 +32,7 @@ module RuboCop return if method_called?(body_node, :head) || find_block(body_node, :head) || find_block(body_node, :devel) + problem STABLE_MSG if stable_block end end diff --git a/Library/Homebrew/rubocops/conflicts_cop.rb b/Library/Homebrew/rubocops/conflicts_cop.rb index c7b37c51ef..ff4d591074 100644 --- a/Library/Homebrew/rubocops/conflicts_cop.rb +++ b/Library/Homebrew/rubocops/conflicts_cop.rb @@ -15,6 +15,7 @@ module RuboCop def audit_formula(_node, _class_node, _parent_class_node, body) return unless versioned_formula? + problem MSG if !@formula_name.start_with?(*WHITELIST) && method_called_ever?(body, :conflicts_with) end diff --git a/Library/Homebrew/rubocops/dependency_order_cop.rb b/Library/Homebrew/rubocops/dependency_order_cop.rb index ab30562532..f660ded598 100644 --- a/Library/Homebrew/rubocops/dependency_order_cop.rb +++ b/Library/Homebrew/rubocops/dependency_order_cop.rb @@ -13,12 +13,14 @@ module RuboCop [:devel, :head, :stable].each do |block_name| block = find_block(body_node, block_name) next unless block + check_dependency_nodes_order(block.body) end end def check_dependency_nodes_order(parent_node) return if parent_node.nil? + dependency_nodes = fetch_depends_on_nodes(parent_node) ordered = dependency_nodes.sort_by { |node| dependency_name(node).downcase } ordered = sort_dependencies_by_type(ordered) @@ -59,9 +61,11 @@ module RuboCop idx = pos+1 match_nodes = build_with_dependency_name(dep) next if !match_nodes || match_nodes.empty? + idx1 = pos ordered.drop(idx1+1).each_with_index do |dep2, pos2| next unless match_nodes.index(dependency_name(dep2)) + idx2 = pos2 if idx2.nil? || pos2 > idx2 end break if idx2 @@ -82,6 +86,7 @@ module RuboCop dependency_node_2 = node2 if l2 < l1 end next unless dependency_node_2 + @offensive_nodes = [dependency_node_1, dependency_node_2] component_problem dependency_node_1, dependency_node_2 end diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb index 73d7c4ae09..7e11c4cd78 100644 --- a/Library/Homebrew/rubocops/extend/formula_cop.rb +++ b/Library/Homebrew/rubocops/extend/formula_cop.rb @@ -23,6 +23,7 @@ module RuboCop return unless file_path_allowed? return unless formula_class?(node) return unless respond_to?(:audit_formula) + class_node, parent_class_node, @body = *node @formula_name = Pathname.new(@file_path).basename(".rb").to_s audit_formula(node, class_node, parent_class_node, @body) @@ -34,6 +35,7 @@ module RuboCop string_repr = string_content(node) match_object = string_repr.match(pattern) return unless match_object + node_begin_pos = start_column(node) line_begin_pos = line_start_column(node) if node_begin_pos == line_begin_pos @@ -58,6 +60,7 @@ module RuboCop url_string = string_content(url_string_node) match_object = regex_match_group(url_string_node, regex) next unless match_object + offending_node(url_string_node.parent) yield match_object, url_string end @@ -67,14 +70,17 @@ module RuboCop def find_strings(node) return [] if node.nil? return [node] if node.str_type? + node.each_descendant(:str) end # Returns method_node matching method_name def find_node_method_by_name(node, method_name) return if node.nil? + node.each_child_node(:send) do |method_node| next unless method_node.method_name == method_name + @offensive_node = method_node @offense_source_range = method_node.source_range return method_node @@ -94,6 +100,7 @@ module RuboCop # Returns an array of method call nodes matching method_name inside node with depth first order (Children nodes) def find_method_calls_by_name(node, method_name) return if node.nil? + node.each_child_node(:send).select { |method_node| method_name == method_node.method_name } end @@ -101,6 +108,7 @@ module RuboCop # Returns every method call if no method_name is passed def find_every_method_call_by_name(node, method_name = nil) return if node.nil? + node.each_descendant(:send).select do |method_node| method_name.nil? || method_name == method_node.method_name @@ -113,6 +121,7 @@ module RuboCop # 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 @@ -125,6 +134,7 @@ module RuboCop methods.each do |method| next unless parameters_passed?(method, *args) return true unless block_given? + yield method end end @@ -140,10 +150,12 @@ module RuboCop methods.each do |method| next if method.receiver.nil? next if method.receiver.const_name != instance && - method.receiver.method_name != instance + !(method.receiver.send_type? && method.receiver.method_name == instance) + @offense_source_range = method.source_range @offensive_node = method return true unless block_given? + yield method end end @@ -156,10 +168,12 @@ module RuboCop node.each_descendant(:send) do |method_node| next if method_node.receiver.nil? next if method_node.receiver.const_name != name && - method_node.receiver.method_name != name + !(method_node.receiver.send_type? && method_node.receiver.method_name == name) + @offense_source_range = method_node.receiver.source_range @offensive_node = method_node.receiver return true unless block_given? + yield method_node end end @@ -173,6 +187,7 @@ module RuboCop types.any? { |type| depends_on_name_type?(n, dependency_name, type) } end return if idx.nil? + @offense_source_range = dependency_nodes[idx].source_range @offensive_node = dependency_nodes[idx] end @@ -212,8 +227,10 @@ module RuboCop # if block given, yield matching nodes def find_const(node, const_name) return if node.nil? + node.each_descendant(:const) do |const_node| next unless const_node.const_name == const_name + @offensive_node = const_node @offense_source_range = const_node.source_range yield const_node if block_given? @@ -246,8 +263,10 @@ module RuboCop # Returns a block named block_name inside node def find_block(node, block_name) return if node.nil? + node.each_child_node(:block) do |block_node| next if block_node.method_name != block_name + @offensive_node = block_node @offense_source_range = block_node.source_range return block_node @@ -261,6 +280,7 @@ module RuboCop # Returns an array of block nodes named block_name inside node def find_blocks(node, block_name) return if node.nil? + node.each_child_node(:block).select { |block_node| block_name == block_node.method_name } end @@ -268,8 +288,10 @@ module RuboCop # If a block is given then yields matching block node to the block! def find_all_blocks(node, block_name) return if node.nil? + blocks = node.each_descendant(:block).select { |block_node| block_name == block_node.method_name } return blocks unless block_given? + blocks.each do |block_node| offending_node(block_node) yield block_node @@ -280,14 +302,17 @@ module RuboCop # Returns first method def if method_name is nil def find_method_def(node, method_name = nil) return if node.nil? + node.each_child_node(:def) do |def_node| def_method_name = method_name(def_node) next unless method_name == def_method_name || method_name.nil? + @offensive_node = def_node @offense_source_range = def_node.source_range return def_node end return if node.parent.nil? + # If not found then, parent node becomes the offensive node @offensive_node = node.parent @offense_source_range = node.parent.source_range @@ -299,6 +324,7 @@ module RuboCop block_body = node.children[2] block_body.each_child_node(:send) do |call_node| next unless call_node.method_name == method_name + @offensive_node = call_node @offense_source_range = call_node.source_range return true @@ -315,6 +341,7 @@ module RuboCop end node.each_child_node(:send) do |call_node| next unless call_node.method_name == method_name + offending_node(call_node) return true end @@ -325,6 +352,7 @@ module RuboCop def method_called_ever?(node, method_name) node.each_descendant(:send) do |call_node| next unless call_node.method_name == method_name + @offensive_node = call_node @offense_source_range = call_node.source_range return true @@ -347,6 +375,7 @@ module RuboCop # If first node does not precede next_node, sets appropriate instance variables for reporting def component_precedes?(first_node, next_node) return false if line_number(first_node) < line_number(next_node) + @offense_source_range = first_node.source_range @offensive_node = first_node true @@ -354,8 +383,9 @@ module RuboCop # Check if negation is present in the given node def expression_negated?(node) - return false if node.parent.nil? + return false unless node.parent&.send_type? return false unless node.parent.method_name.equal?(:!) + offending_node(node.parent) end @@ -390,6 +420,7 @@ module RuboCop # Returns the sha256 str node given a sha256 call node def get_checksum_node(call) return if parameters(call).empty? || parameters(call).nil? + if parameters(call).first.str_type? parameters(call).first # sha256 is passed as a key-value pair in bottle blocks @@ -478,12 +509,14 @@ module RuboCop # Returns printable component name def format_component(component_node) return component_node.method_name if component_node.send_type? || component_node.block_type? + method_name(component_node) if component_node.def_type? end # Returns the formula tap def formula_tap return unless match_obj = @file_path.match(%r{/(homebrew-\w+)/}) + match_obj[1] end @@ -509,6 +542,7 @@ module RuboCop paths_to_exclude = [%r{/Library/Homebrew/compat/}, %r{/Library/Homebrew/test/}] return true if @file_path.nil? # file_path is nil when source is directly passed to the cop eg., in specs + @file_path !~ Regexp.union(paths_to_exclude) end end diff --git a/Library/Homebrew/rubocops/formula_desc_cop.rb b/Library/Homebrew/rubocops/formula_desc_cop.rb index 5d3483f661..c41313fbfe 100644 --- a/Library/Homebrew/rubocops/formula_desc_cop.rb +++ b/Library/Homebrew/rubocops/formula_desc_cop.rb @@ -29,6 +29,7 @@ module RuboCop desc_length = "#{@formula_name}: #{string_content(desc)}".length max_desc_length = 80 return if desc_length <= max_desc_length + problem "Description is too long. \"name: desc\" should be less than #{max_desc_length} characters. " \ "Length is calculated as #{@formula_name} + desc. (currently #{desc_length})" end @@ -98,6 +99,7 @@ module RuboCop # Check if a full stop is used at the end of a formula's desc (apart from in the case of "etc.") return unless regex_match_group(desc, /\.$/) && !string_content(desc).end_with?("etc.") + problem "Description shouldn't end with a full stop" end diff --git a/Library/Homebrew/rubocops/lines_cop.rb b/Library/Homebrew/rubocops/lines_cop.rb index 6a17fd2fc6..ca5dbc4c1d 100644 --- a/Library/Homebrew/rubocops/lines_cop.rb +++ b/Library/Homebrew/rubocops/lines_cop.rb @@ -9,12 +9,14 @@ module RuboCop [:automake, :ant, :autoconf, :emacs, :expat, :libtool, :mysql, :perl, :postgresql, :python, :python3, :rbenv, :ruby].each do |dependency| next unless depends_on?(dependency) + problem ":#{dependency} is deprecated. Usage should be \"#{dependency}\"." end { apr: "apr-util", fortran: "gcc", gpg: "gnupg", hg: "mercurial", mpi: "open-mpi", python2: "python" }.each do |requirement, dependency| next unless depends_on?(requirement) + problem ":#{requirement} is deprecated. Usage should be \"#{dependency}\"." end @@ -27,6 +29,7 @@ module RuboCop begin_pos = start_column(parent_class_node) end_pos = end_column(class_node) return unless begin_pos-end_pos != 3 + problem "Use a space in class inheritance: " \ "class #{@formula_name.capitalize} < #{class_name(parent_class_node)}" end @@ -47,6 +50,7 @@ module RuboCop '# system "cmake', ].each do |template_comment| next unless comment.include?(template_comment) + problem "Please remove default template comments" break end @@ -55,6 +59,7 @@ module RuboCop audit_comments do |comment| # Commented-out depends_on next unless comment =~ /#\s*depends_on\s+(.+)\s*$/ + problem "Commented-out dependency #{Regexp.last_match(1)}" end end @@ -90,29 +95,34 @@ module RuboCop find_instance_method_call(body_node, :build, :without?) do |method| next unless unless_modifier?(method.parent) + correct = method.source.gsub("out?", "?") problem "Use if #{correct} instead of unless #{method.source}" end find_instance_method_call(body_node, :build, :with?) do |method| next unless unless_modifier?(method.parent) + correct = method.source.gsub("?", "out?") problem "Use if #{correct} instead of unless #{method.source}" end find_instance_method_call(body_node, :build, :with?) do |method| next unless expression_negated?(method) + problem "Don't negate 'build.with?': use 'build.without?'" end find_instance_method_call(body_node, :build, :without?) do |method| next unless expression_negated?(method) + problem "Don't negate 'build.without?': use 'build.with?'" end find_instance_method_call(body_node, :build, :without?) do |method| arg = parameters(method).first next unless match = regex_match_group(arg, /^-?-?without-(.*)/) + problem "Don't duplicate 'without': " \ "Use `build.without? \"#{match[1]}\"` to check for \"--without-#{match[1]}\"" end @@ -120,12 +130,14 @@ module RuboCop find_instance_method_call(body_node, :build, :with?) do |method| arg = parameters(method).first next unless match = regex_match_group(arg, /^-?-?with-(.*)/) + problem "Don't duplicate 'with': Use `build.with? \"#{match[1]}\"` to check for \"--with-#{match[1]}\"" end find_instance_method_call(body_node, :build, :include?) do |method| arg = parameters(method).first next unless match = regex_match_group(arg, /^with(out)?-(.*)/) + problem "Use build.with#{match[1]}? \"#{match[2]}\" instead of " \ "build.include? 'with#{match[1]}-#{match[2]}'" end @@ -133,12 +145,14 @@ module RuboCop find_instance_method_call(body_node, :build, :include?) do |method| arg = parameters(method).first next unless match = regex_match_group(arg, /^\-\-(.*)$/) + problem "Reference '#{match[1]}' without dashes" end end def unless_modifier?(node) return false unless node.if_type? + node.modifier_form? && node.unless? end end @@ -155,6 +169,7 @@ module RuboCop find_all_blocks(body_node, :inreplace) do |node| block_arg = node.arguments.children.first next unless block_arg.source.size > 1 + problem "\"inreplace do |s|\" is preferred over \"|#{block_arg.source}|\"." end @@ -166,6 +181,7 @@ module RuboCop [:mac?, :linux?].each do |method_name| next unless formula_tap == "homebrew-core" + find_instance_method_call(body_node, "OS", method_name) do |check| problem "Don't use #{check.source}; Homebrew/core only supports macOS" end @@ -173,11 +189,13 @@ module RuboCop find_instance_call(body_node, "ARGV") do |method_node| next if [:debug?, :verbose?, :value].index(method_node.method_name) + problem "Use build instead of ARGV to check options" end find_instance_method_call(body_node, :man, :+) do |method| next unless match = regex_match_group(parameters(method).first, /^man[1-8]$/) + problem "\"#{method.source}\" should be \"#{match[0]}\"" end @@ -203,6 +221,7 @@ module RuboCop # Prefer formula path shortcuts in strings formula_path_strings(body_node, :share) do |p| next unless match = regex_match_group(p, %r{^(/(man))/?}) + problem "\"\#{share}#{match[1]}\" should be \"\#{#{match[2]}}\"" end @@ -222,11 +241,13 @@ module RuboCop key, value = destructure_hash(parameters(method).first) next if key.nil? || value.nil? next unless match = regex_match_group(value, /^(lua|perl|python|ruby)(\d*)/) + problem "#{match[1]} modules should be vendored rather than use deprecated #{method.source}`" end find_every_method_call_by_name(body_node, :system).each do |method| next unless match = regex_match_group(parameters(method).first, /^(env|export)(\s+)?/) + problem "Use ENV instead of invoking '#{match[1]}' to modify the environment" end @@ -234,9 +255,11 @@ module RuboCop param = parameters(method).first dep, option_child_nodes = hash_dep(param) next if dep.nil? || option_child_nodes.empty? + option_child_nodes.each do |option| find_strings(option).each do |dependency| next unless match = regex_match_group(dependency, /(with(out)?-\w+|c\+\+11)/) + problem "Dependency #{string_content(dep)} should not use option #{match[0]}" end end @@ -244,12 +267,14 @@ module RuboCop find_instance_method_call(body_node, :version, :==) do |method| next unless parameters_passed?(method, "HEAD") + problem "Use 'build.head?' instead of inspecting 'version'" end find_instance_method_call(body_node, "ARGV", :include?) do |method| param = parameters(method).first next unless match = regex_match_group(param, /^--(HEAD|devel)/) + problem "Use \"if build.#{match[1].downcase}?\" instead" end @@ -288,15 +313,18 @@ module RuboCop find_method_with_args(body_node, :system, /^(otool|install_name_tool|lipo)/) do next if @formula_name == "cctools" + problem "Use ruby-macho instead of calling #{@offensive_node.source}" end find_every_method_call_by_name(body_node, :system).each do |method_node| # Skip Kibana: npm cache edge (see formula for more details) next if @formula_name =~ /^kibana(@\d[\d.]*)?$/ + first_param, second_param = parameters(method_node) next if !node_equals?(first_param, "npm") || !node_equals?(second_param, "install") + offending_node(method_node) problem "Use Language::Node for npm install args" unless languageNodeModule?(method_node) end @@ -316,11 +344,13 @@ module RuboCop find_instance_method_call(body_node, :build, :universal?) do next if @formula_name == "wine" + problem "macOS has been 64-bit only since 10.6 so build.universal? is deprecated." end find_instance_method_call(body_node, "ENV", :universal_binary) do next if @formula_name == "wine" + problem "macOS has been 64-bit only since 10.6 so ENV.universal_binary is deprecated." end @@ -330,6 +360,7 @@ module RuboCop find_every_method_call_by_name(body_node, :depends_on).each do |method| next unless method_called?(method, :new) + problem "`depends_on` can take requirement classes instead of instances" end @@ -342,9 +373,11 @@ module RuboCop find_instance_method_call(body_node, "Dir", :[]) do |method| next unless parameters(method).size == 1 + path = parameters(method).first next unless path.str_type? next unless match = regex_match_group(path, /^[^\*{},]+$/) + problem "Dir([\"#{string_content(path)}\"]) is unnecessary; just use \"#{match[0]}\"" end @@ -356,12 +389,14 @@ module RuboCop find_every_method_call_by_name(body_node, :system).each do |method| param = parameters(method).first next unless match = regex_match_group(param, fileutils_methods) + problem "Use the `#{match}` Ruby method instead of `#{method.source}`" end end def modifier?(node) return false unless node.if_type? + node.modifier_form? end diff --git a/Library/Homebrew/rubocops/options_cop.rb b/Library/Homebrew/rubocops/options_cop.rb index db20d9576f..e16681e58b 100644 --- a/Library/Homebrew/rubocops/options_cop.rb +++ b/Library/Homebrew/rubocops/options_cop.rb @@ -37,6 +37,7 @@ module RuboCop next unless option =~ /^with(out)?-(?:checks?|tests)$/ next if depends_on?("check", :optional, :recommended) + problem "Use '--with#{Regexp.last_match(1)}-test' instead of '--#{option}'."\ " Migrate '--#{option}' with `deprecated_option`." end @@ -52,6 +53,7 @@ module RuboCop def audit_formula(_node, _class_node, _parent_class_node, body_node) problem DEP_OPTION if method_called_ever?(body_node, :deprecated_option) return unless formula_tap == "homebrew-core" + problem OPTION if method_called_ever?(body_node, :option) end end diff --git a/Library/Homebrew/rubocops/patches_cop.rb b/Library/Homebrew/rubocops/patches_cop.rb index 338fcf2355..b7b632ae16 100644 --- a/Library/Homebrew/rubocops/patches_cop.rb +++ b/Library/Homebrew/rubocops/patches_cop.rb @@ -16,6 +16,7 @@ module RuboCop patches_node = find_method_def(body, :patches) return if patches_node.nil? + legacy_patches = find_strings(patches_node) problem "Use the patch DSL instead of defining a 'patches' method" legacy_patches.each { |p| patch_problems(p) } @@ -74,6 +75,7 @@ module RuboCop end return unless regex_match_group(patch, %r{^http://bugs\.debian\.org}) + problem <<~EOS.chomp Patches from Debian should be https://, not http: #{patch_url} diff --git a/Library/Homebrew/rubocops/text_cop.rb b/Library/Homebrew/rubocops/text_cop.rb index 0ca6bce28f..72d01524f5 100644 --- a/Library/Homebrew/rubocops/text_cop.rb +++ b/Library/Homebrew/rubocops/text_cop.rb @@ -34,6 +34,7 @@ module RuboCop find_every_method_call_by_name(body_node, :xcodebuild).each do |m| next if parameters_passed?(m, /SYMROOT=/) + problem 'xcodebuild should be passed an explicit "SYMROOT"' end @@ -51,6 +52,7 @@ module RuboCop find_method_with_args(body_node, :system, "dep", "ensure") do |d| next if parameters_passed?(d, /vendor-only/) + problem "use \"dep\", \"ensure\", \"-vendor-only\"" end diff --git a/Library/Homebrew/rubocops/urls_cop.rb b/Library/Homebrew/rubocops/urls_cop.rb index 0dfe5158b4..ec8d7415ac 100644 --- a/Library/Homebrew/rubocops/urls_cop.rb +++ b/Library/Homebrew/rubocops/urls_cop.rb @@ -26,6 +26,7 @@ module RuboCop urls.each do |url| url_string = string_content(parameters(url).first) next unless url_string.eql?(mirror) + problem "URL should not be duplicated as a mirror: #{url_string}" end end @@ -163,6 +164,7 @@ module RuboCop archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/} audit_urls(urls, archive_gh_pattern) do |_, url| next unless url !~ /\.git$/ + problem "Use /archive/ URLs for GitHub tarballs (url is #{url})." end @@ -170,6 +172,7 @@ module RuboCop zip_gh_pattern = %r{https://.*github.*/(archive|releases)/.*\.zip$} audit_urls(urls, zip_gh_pattern) do |_, url| next unless url !~ %r{releases/download} + problem "Use GitHub tarballs rather than zipballs (url is #{url})." end diff --git a/Library/Homebrew/sandbox.rb b/Library/Homebrew/sandbox.rb index 6ec24a8367..b55ffc7856 100644 --- a/Library/Homebrew/sandbox.rb +++ b/Library/Homebrew/sandbox.rb @@ -10,11 +10,13 @@ class Sandbox def self.formula?(_formula) return false unless available? + !ARGV.no_sandbox? end def self.test? return false unless available? + !ARGV.no_sandbox? end @@ -135,6 +137,7 @@ class Sandbox def expand_realpath(path) raise unless path.absolute? + path.exist? ? path.realpath : expand_realpath(path.parent)/path.basename end diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index 10a788aafa..b7a81d645d 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -71,12 +71,14 @@ class SoftwareSpec def url(val = nil, specs = {}) return @resource.url if val.nil? + @resource.url(val, specs) dependency_collector.add(@resource) end def bottle_unneeded? return false unless @bottle_disable_reason + @bottle_disable_reason.unneeded? end @@ -110,6 +112,7 @@ class SoftwareSpec def resource(name, klass = Resource, &block) if block_given? raise DuplicateResourceError, name if resource_defined?(name) + res = klass.new(name, &block) resources[name] = res dependency_collector.add(res) @@ -138,6 +141,7 @@ class SoftwareSpec raise ArgumentError, "option name is required" if name.empty? raise ArgumentError, "option name must be longer than one character: #{name}" unless name.length > 1 raise ArgumentError, "option name must not start with dashes: #{name}" if name.start_with?("-") + Option.new(name, description) end options << opt @@ -145,6 +149,7 @@ class SoftwareSpec def deprecated_option(hash) raise ArgumentError, "deprecated_option hash must not be empty" if hash.empty? + hash.each do |old_options, new_options| Array(old_options).each do |old_option| Array(new_options).each do |new_option| @@ -154,6 +159,7 @@ class SoftwareSpec old_flag = deprecated_option.old_flag new_flag = deprecated_option.current_flag next unless @flags.include? old_flag + @flags -= [old_flag] @flags |= [new_flag] @deprecated_flags << deprecated_option diff --git a/Library/Homebrew/style.rb b/Library/Homebrew/style.rb index 8490edf005..bbfee6cf33 100644 --- a/Library/Homebrew/style.rb +++ b/Library/Homebrew/style.rb @@ -103,6 +103,7 @@ module Homebrew if !(0..1).cover?(status.exitstatus) || json.to_s.length < 2 raise "Error running `rubocop --format json #{args.join " "}`\n#{err}" end + RubocopResults.new(JSON.parse(json)) else raise "Invalid output_type for check_style_impl: #{output_type}" @@ -115,6 +116,7 @@ module Homebrew @file_offenses = {} json["files"].each do |f| next if f["offenses"].empty? + file = File.realpath(f["path"]) @file_offenses[file] = f["offenses"].map { |x| RubocopOffense.new(x) } end diff --git a/Library/Homebrew/system_command.rb b/Library/Homebrew/system_command.rb index c1614cc95d..fa0c678b7a 100644 --- a/Library/Homebrew/system_command.rb +++ b/Library/Homebrew/system_command.rb @@ -92,12 +92,14 @@ class SystemCommand def sudo_prefix return [] unless sudo? + askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : [] ["/usr/bin/sudo", *askpass_flags, "-E", "--"] end def assert_success return if @status.success? + raise ErrorDuringExecution.new(command, status: @status, output: @output) @@ -212,6 +214,7 @@ class SystemCommand def warn_plist_garbage(garbage) return unless ARGV.verbose? return unless garbage =~ /\S/ + opoo "Received non-XML output from #{Formatter.identifier(command.first)}:" $stderr.puts garbage.strip end diff --git a/Library/Homebrew/system_config.rb b/Library/Homebrew/system_config.rb index 4d26c6edbb..d70a43534c 100644 --- a/Library/Homebrew/system_config.rb +++ b/Library/Homebrew/system_config.rb @@ -47,6 +47,7 @@ class SystemConfig def describe_path(path) return "N/A" if path.nil? + realpath = path.realpath if realpath == path path @@ -70,6 +71,7 @@ class SystemConfig def hardware return if Hardware::CPU.type == :dunno + "CPU: #{Hardware.cores_as_words}-core #{Hardware::CPU.bits}-bit #{Hardware::CPU.family}" end @@ -79,13 +81,16 @@ class SystemConfig def describe_java return "N/A" unless which "java" + _, err, status = system_command("java", args: ["-version"], print_stderr: false) return "N/A" unless status.success? + err[/java version "([\d\._]+)"/, 1] || "N/A" end def describe_git return "N/A" unless Utils.git_available? + "#{Utils.git_version} => #{Utils.git_path}" end @@ -166,6 +171,7 @@ class SystemConfig 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 diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb index aa9bea684e..76ba9ebb0f 100644 --- a/Library/Homebrew/tab.rb +++ b/Library/Homebrew/tab.rb @@ -121,6 +121,7 @@ class Tab < OpenStruct deprecated_options.each do |deprecated_option| option = options.find { |o| o.name == deprecated_option.old } next unless option + options -= [option] options << Option.new(deprecated_option.current, option.description) end @@ -265,6 +266,7 @@ class Tab < OpenStruct def parsed_homebrew_version return Version::NULL if homebrew_version.nil? + Version.new(homebrew_version) end diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 8f11bb110b..01f4b1e222 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -40,6 +40,7 @@ class Tap def self.from_path(path) match = File.expand_path(path).match(HOMEBREW_TAP_PATH_REGEX) raise "Invalid tap path '#{path}'" unless match + fetch(match[:user], match[:repo]) rescue # No need to error as a nil tap is sufficient to show failure. @@ -109,6 +110,7 @@ class Tap # e.g. `https://github.com/user/homebrew-repo` def remote raise TapUnavailableError, name unless installed? + @remote ||= path.git_origin end @@ -132,30 +134,35 @@ class Tap # git branch for this {Tap}. def git_branch raise TapUnavailableError, name unless installed? + path.git_branch end # git HEAD for this {Tap}. def git_head raise TapUnavailableError, name unless installed? + path.git_head end # git HEAD in short format for this {Tap}. def git_short_head raise TapUnavailableError, name unless installed? + path.git_short_head end # time since git last commit for this {Tap}. def git_last_commit raise TapUnavailableError, name unless installed? + path.git_last_commit end # git last commit date for this {Tap}. def git_last_commit_date raise TapUnavailableError, name unless installed? + path.git_last_commit_date end @@ -163,6 +170,7 @@ class Tap # e.g. `https://github.com/user/homebrew-repo/issues` def issues_url return unless official? || !custom_remote? + "#{default_remote}/issues" end @@ -172,8 +180,10 @@ class Tap def version_string return "N/A" unless installed? + pretty_revision = git_short_head return "(no git repository)" unless pretty_revision + "(git revision #{pretty_revision}; last commit #{git_last_commit_date})" end @@ -185,6 +195,7 @@ class Tap # True if the remote of this {Tap} is a private repository. def private? return @private if instance_variable_defined?(:@private) + @private = read_or_set_private_config end @@ -192,6 +203,7 @@ class Tap def config @config ||= begin raise TapUnavailableError, name unless installed? + TapConfig.new(self) end end @@ -292,6 +304,7 @@ class Tap return if options[:clone_target] return unless private? return if quiet + puts <<~EOS It looks like you tapped a private repository. To avoid entering your credentials each time you update, you can use git HTTP credential @@ -330,6 +343,7 @@ class Tap # True if the {#remote} of {Tap} is customized. def custom_remote? return true unless remote + remote.casecmp(default_remote).nonzero? end @@ -428,6 +442,7 @@ class Tap # @private def alias_table return @alias_table if @alias_table + @alias_table = {} alias_files.each do |alias_file| @alias_table[alias_file_to_name(alias_file)] = formula_file_to_name(alias_file.resolved_path) @@ -439,6 +454,7 @@ class Tap # @private def alias_reverse_table return @alias_reverse_table if @alias_reverse_table + @alias_reverse_table = {} alias_table.each do |alias_name, formula_name| @alias_reverse_table[formula_name] ||= [] @@ -476,6 +492,7 @@ class Tap # True if this {Tap} has been pinned. def pinned? return @pinned if instance_variable_defined?(:@pinned) + @pinned = pinned_symlink_path.directory? end @@ -483,6 +500,7 @@ class Tap def pin raise TapUnavailableError, name unless installed? raise TapPinStatusError.new(name, true) if pinned? + pinned_symlink_path.make_relative_symlink(path) @pinned = true end @@ -491,6 +509,7 @@ class Tap def unpin raise TapUnavailableError, name unless installed? raise TapPinStatusError.new(name, false) unless pinned? + pinned_symlink_path.delete pinned_symlink_path.parent.rmdir_if_possible pinned_symlink_path.parent.parent.rmdir_if_possible @@ -618,6 +637,7 @@ class CoreTap < Tap def self.ensure_installed! return if instance.installed? + safe_system HOMEBREW_BREW_FILE, "tap", instance.name end diff --git a/Library/Homebrew/test/Gemfile.lock b/Library/Homebrew/test/Gemfile.lock index da013e731b..e55090369c 100644 --- a/Library/Homebrew/test/Gemfile.lock +++ b/Library/Homebrew/test/Gemfile.lock @@ -37,7 +37,7 @@ GEM rspec-support (3.8.0) rspec-wait (0.0.9) rspec (>= 3, < 4) - rubocop (0.58.2) + rubocop (0.59.1) jaro_winkler (~> 1.5.1) parallel (~> 1.10) parser (>= 2.5, != 2.5.1.1) @@ -64,7 +64,7 @@ DEPENDENCIES rspec-its rspec-retry rspec-wait - rubocop (= 0.58.2) + rubocop (= 0.59.1) simplecov BUNDLED WITH diff --git a/Library/Homebrew/test/support/helper/cask/fake_system_command.rb b/Library/Homebrew/test/support/helper/cask/fake_system_command.rb index 2769683d84..457b64de61 100644 --- a/Library/Homebrew/test/support/helper/cask/fake_system_command.rb +++ b/Library/Homebrew/test/support/helper/cask/fake_system_command.rb @@ -46,6 +46,7 @@ class FakeSystemCommand unless responses.key?(command) raise("no response faked for #{command.inspect}, faked responses are: #{responses.inspect}") end + system_calls[command] += 1 response = responses[command] diff --git a/Library/Homebrew/test/support/helper/mktmpdir.rb b/Library/Homebrew/test/support/helper/mktmpdir.rb index f08fd386b4..651d08e541 100644 --- a/Library/Homebrew/test/support/helper/mktmpdir.rb +++ b/Library/Homebrew/test/support/helper/mktmpdir.rb @@ -4,6 +4,7 @@ module Test def mktmpdir(prefix_suffix = nil) new_dir = Pathname.new(Dir.mktmpdir(prefix_suffix, HOMEBREW_TEMP)) return yield new_dir if block_given? + new_dir end end diff --git a/Library/Homebrew/test/support/helper/output_as_tty.rb b/Library/Homebrew/test/support/helper/output_as_tty.rb index 22f96510e3..eb5d4c219b 100644 --- a/Library/Homebrew/test/support/helper/output_as_tty.rb +++ b/Library/Homebrew/test/support/helper/output_as_tty.rb @@ -65,12 +65,14 @@ module Test def as_tty @tty = true return self if [:stdout, :stderr].include?(@output) + raise "`as_tty` can only be chained to `stdout` or `stderr`." end def with_color @colors = true return self if @tty + raise "`with_color` can only be chained to `as_tty`." end end diff --git a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb index e1ac4bbcbf..2937c60f74 100644 --- a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb +++ b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb @@ -100,6 +100,7 @@ RSpec.shared_context "integration test" do # full_require_paths isn't available in RubyGems < 2.2. spec.require_paths.map do |lib| next lib if lib.include?(full_gem_path) + "#{full_gem_path}/#{lib}" end end diff --git a/Library/Homebrew/unpack_strategy/dmg.rb b/Library/Homebrew/unpack_strategy/dmg.rb index 5068a57fc5..40557d82c2 100644 --- a/Library/Homebrew/unpack_strategy/dmg.rb +++ b/Library/Homebrew/unpack_strategy/dmg.rb @@ -69,6 +69,7 @@ module UnpackStrategy end rescue ErrorDuringExecution => e raise e if (tries -= 1).zero? + sleep 1 retry end diff --git a/Library/Homebrew/update_migrator.rb b/Library/Homebrew/update_migrator.rb index 0ee2b803cb..467df09d59 100644 --- a/Library/Homebrew/update_migrator.rb +++ b/Library/Homebrew/update_migrator.rb @@ -176,6 +176,7 @@ module UpdateMigrator return if migration_attempted_file.exist? return unless legacy_cache.writable_real? + FileUtils.touch migration_attempted_file # This directory could have been compromised if it's world-writable/ @@ -190,6 +191,7 @@ module UpdateMigrator legacy_cache.cd do legacy_cache.entries.each do |f| next if [".", "..", ".migration_attempted"].include? f.to_s + begin FileUtils.cp_r f, HOMEBREW_CACHE rescue diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index a29d494ff9..58a10538d3 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -16,6 +16,7 @@ require "time" def require?(path) return false if path.nil? + require path true rescue LoadError => e @@ -31,6 +32,7 @@ end def odebug(title, *sput) return unless ARGV.debug? + puts Formatter.headline(title, color: :magenta) puts sput unless sput.empty? end @@ -99,6 +101,7 @@ def odeprecated(method, replacement = nil, disable: false, disable_on: nil, call backtrace.each do |line| next unless match = line.match(HOMEBREW_TAP_PATH_REGEX) + tap = Tap.fetch(match[:user], match[:repo]) tap_message = "\nPlease report this to the #{tap} tap" tap_message += ", or even better, submit a PR to fix it" if replacement @@ -152,6 +155,7 @@ def pretty_duration(s) s %= 60 res = Formatter.pluralize(m, "minute") return res if s.zero? + res << " " end @@ -173,6 +177,7 @@ def interactive_shell(f = nil) return if $CHILD_STATUS.success? raise "Aborted due to non-zero exit status (#{$CHILD_STATUS.exitstatus})" if $CHILD_STATUS.exited? + raise $CHILD_STATUS.inspect end @@ -238,6 +243,7 @@ module Homebrew install_gem!(name, version) return if which(executable) + odie <<~EOS The '#{name}' gem is installed but couldn't find '#{executable}' in the PATH: #{ENV["PATH"]} @@ -252,6 +258,7 @@ module Homebrew the_module.module_eval do instance_methods.grep(pattern).each do |name| next if injected_methods.include? name + method = instance_method(name) define_method(name) do |*args, &block| begin @@ -266,6 +273,7 @@ module Homebrew end return unless $times.nil? + $times = {} at_exit do col_width = [$times.keys.map(&:size).max + 2, 15].max @@ -298,6 +306,7 @@ end # Kernel.system but with exceptions def safe_system(cmd, *args, **options) return if Homebrew.system(cmd, *args, **options) + raise(ErrorDuringExecution.new([cmd, *args], status: $CHILD_STATUS)) end @@ -369,6 +378,7 @@ def exec_browser(*args) browser = ENV["HOMEBREW_BROWSER"] browser ||= OS::PATH_OPEN if defined?(OS::PATH_OPEN) return unless browser + safe_exec(browser, *args) end diff --git a/Library/Homebrew/utils/analytics.rb b/Library/Homebrew/utils/analytics.rb index f52d9ab722..3f9f4c71dd 100644 --- a/Library/Homebrew/utils/analytics.rb +++ b/Library/Homebrew/utils/analytics.rb @@ -9,6 +9,7 @@ module Utils def clear_os_prefix_ci return unless instance_variable_defined?(:@os_prefix_ci) + remove_instance_variable(:@os_prefix_ci) end @@ -43,6 +44,7 @@ module Utils metadata.each do |key, value| next unless key next unless value + key = ERB::Util.url_encode key value = ERB::Util.url_encode value args << "--data" << "#{key}=#{value}" @@ -79,6 +81,7 @@ module Utils return unless exception.formula.tap return unless exception.formula.tap.installed? return if exception.formula.tap.private? + action = exception.formula.full_name if (options = exception.options) action = "#{action} #{options}".strip diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index f67ace4c19..648c3d88b1 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -10,6 +10,7 @@ module Utils def built_as?(f) return false unless f.installed? + tab = Tab.for_keg(f.installed_prefix) tab.built_as_bottle end @@ -33,6 +34,7 @@ module Utils line =~ %r{.+/.+/INSTALL_RECEIPT.json} end raise "This bottle does not contain the file INSTALL_RECEIPT.json: #{bottle_file}" unless path + path end @@ -61,6 +63,7 @@ module Utils formula_path = "#{name}/#{bottle_version}/.brew/#{name}.rb" contents = Utils.popen_read "tar", "-xOzf", bottle_file, formula_path raise BottleFormulaUnavailableError.new(bottle_file, formula_path) unless $CHILD_STATUS.success? + contents end end diff --git a/Library/Homebrew/utils/curl.rb b/Library/Homebrew/utils/curl.rb index 40e8f26380..8df5615d4b 100644 --- a/Library/Homebrew/utils/curl.rb +++ b/Library/Homebrew/utils/curl.rb @@ -7,6 +7,7 @@ def curl_executable "/usr/bin/curl", ].compact.map { |c| Pathname(c) }.find(&:executable?) raise "no executable curl was found" unless @curl + @curl end @@ -83,6 +84,7 @@ def curl_check_http_content(url, user_agents: [:default], check_content: false, unless details[:status] # Hack around https://github.com/Homebrew/brew/issues/3199 return if MacOS.version == :el_capitan + return "The URL #{url} is not reachable" end @@ -133,6 +135,7 @@ def curl_check_http_content(url, user_agents: [:default], check_content: false, lenratio = (100 * secure_details[:file].length / details[:file].length).to_i return unless (90..110).cover?(lenratio) + "The URL #{url} may be able to use HTTPS rather than HTTP. Please verify it in a browser." end diff --git a/Library/Homebrew/utils/git.rb b/Library/Homebrew/utils/git.rb index 7846389c8a..5238c8ccca 100644 --- a/Library/Homebrew/utils/git.rb +++ b/Library/Homebrew/utils/git.rb @@ -33,6 +33,7 @@ module Utils def self.git_path return unless git_available? + @git_path ||= Utils.popen_read( HOMEBREW_SHIMS_PATH/"scm/git", "--homebrew=print-path" ).chuzzle @@ -40,6 +41,7 @@ module Utils def self.git_version return unless git_available? + @git_version ||= Utils.popen_read( HOMEBREW_SHIMS_PATH/"scm/git", "--version" ).chomp[/git version (\d+(?:\.\d+)*)/, 1] @@ -69,6 +71,7 @@ module Utils def self.git_remote_exists?(url) return true unless git_available? + quiet_system "git", "ls-remote", url end end diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index e697b8f38f..e6fc4ef43a 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -92,6 +92,7 @@ module GitHub token, username = api_credentials return :none if !token || token.empty? return :environment if !username || username.empty? + :keychain end @@ -197,6 +198,7 @@ module GitHub key, _, value = l.delete(":").partition(" ") key = key.downcase.strip next if key.empty? + meta[key] = value.strip end @@ -297,6 +299,7 @@ module GitHub def create_issue_comment(body) return false unless PR_ENV + _, user, repo, pr = *PR_ENV.match(HOMEBREW_PULL_OR_COMMIT_URL_REGEX) if !user || !repo || !pr opoo <<-EOS.undent @@ -321,6 +324,7 @@ module GitHub url = "#{API_URL}/repos/#{user}/#{repo}/issues/#{pr}/comments" comments = open_api(url) return unless comments + comments.any? { |comment| comment["body"].eql?(body) } end diff --git a/Library/Homebrew/utils/link.rb b/Library/Homebrew/utils/link.rb index 96bfd602e3..a40467334d 100644 --- a/Library/Homebrew/utils/link.rb +++ b/Library/Homebrew/utils/link.rb @@ -4,13 +4,16 @@ module Utils def link_src_dst_dirs(src_dir, dst_dir, command, link_dir: false) return unless src_dir.exist? + conflicts = [] src_paths = link_dir ? [src_dir] : src_dir.find src_paths.each do |src| next if src.directory? && !link_dir + dst = dst_dir/src.relative_path_from(src_dir) if dst.symlink? next if src == dst.resolved_path + dst.unlink end if dst.exist? @@ -22,6 +25,7 @@ module Utils end return if conflicts.empty? + onoe <<~EOS Could not link: #{conflicts.join("\n")} @@ -33,9 +37,11 @@ module Utils def unlink_src_dst_dirs(src_dir, dst_dir, unlink_dir: false) return unless src_dir.exist? + src_paths = unlink_dir ? [src_dir] : src_dir.find src_paths.each do |src| next if src.directory? && !unlink_dir + dst = dst_dir/src.relative_path_from(src_dir) dst.delete if dst.symlink? && src == dst.resolved_path dst.parent.rmdir_if_possible diff --git a/Library/Homebrew/utils/popen.rb b/Library/Homebrew/utils/popen.rb index 8c7adff27a..fe80042310 100644 --- a/Library/Homebrew/utils/popen.rb +++ b/Library/Homebrew/utils/popen.rb @@ -6,6 +6,7 @@ module Utils def self.safe_popen_read(*args, **options, &block) output = popen_read(*args, **options, &block) return output if $CHILD_STATUS.success? + raise ErrorDuringExecution.new(args, status: $CHILD_STATUS, output: [[:stdout, output]]) end @@ -16,6 +17,7 @@ module Utils def self.safe_popen_write(*args, **options, &block) output = popen_write(*args, **options, &block) return output if $CHILD_STATUS.success? + raise ErrorDuringExecution.new(args, status: $CHILD_STATUS, output: [[:stdout, output]]) end @@ -23,6 +25,7 @@ module Utils IO.popen("-", mode) do |pipe| if pipe return pipe.read unless block_given? + yield pipe else options[:err] ||= :close unless ENV["HOMEBREW_STDERR"] diff --git a/Library/Homebrew/utils/shell.rb b/Library/Homebrew/utils/shell.rb index fb602a2726..9a886ca40d 100644 --- a/Library/Homebrew/utils/shell.rb +++ b/Library/Homebrew/utils/shell.rb @@ -78,6 +78,7 @@ module Utils # ruby's implementation of shell_escape str = str.to_s return "''" if str.empty? + str = str.dup # anything that isn't a known safe character is padded str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1") @@ -90,6 +91,7 @@ module Utils # ruby's implementation of shell_escape str = str.to_s return "''" if str.empty? + str = str.dup # anything that isn't a known safe character is padded str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1") diff --git a/Library/Homebrew/utils/svn.rb b/Library/Homebrew/utils/svn.rb index ffed58a1a2..b824e0d064 100644 --- a/Library/Homebrew/utils/svn.rb +++ b/Library/Homebrew/utils/svn.rb @@ -5,11 +5,13 @@ module Utils def self.svn_available? return @svn if instance_variable_defined?(:@svn) + @svn = quiet_system HOMEBREW_SHIMS_PATH/"scm/svn", "--version" end def self.svn_remote_exists?(url) return true unless svn_available? + ssl_args = ["--non-interactive", "--trust-server-cert"] if ENV["HOMEBREW_TEST_ONLINE"] quiet_system "svn", "ls", url, "--depth", "empty", *ssl_args end diff --git a/Library/Homebrew/utils/tty.rb b/Library/Homebrew/utils/tty.rb index fb53968c5f..f52c874d97 100644 --- a/Library/Homebrew/utils/tty.rb +++ b/Library/Homebrew/utils/tty.rb @@ -47,6 +47,7 @@ module Tty def current_escape_sequence return "" if @escape_sequence.nil? + "\033[#{@escape_sequence.join(";")}m" end @@ -64,6 +65,7 @@ module Tty if !ENV["HOMEBREW_COLOR"] && (ENV["HOMEBREW_NO_COLOR"] || !$stdout.tty?) return "" end + current_escape_sequence ensure reset_escape_sequence! diff --git a/Library/Homebrew/version.rb b/Library/Homebrew/version.rb index 44253b17a1..8dfe839fde 100644 --- a/Library/Homebrew/version.rb +++ b/Library/Homebrew/version.rb @@ -368,6 +368,7 @@ class Version unless val.respond_to?(:to_str) raise TypeError, "Version value must be a string; got a #{val.class} (#{val})" end + @version = val.to_str end @@ -415,9 +416,11 @@ class Version return a <=> b elsif a.numeric? return 1 if a > NULL_TOKEN + l += 1 elsif b.numeric? return -1 if b > NULL_TOKEN + r += 1 else return a <=> b