diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index 277f233905..93cb79cd4e 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -58,7 +58,7 @@ GEM mime-types-data (3.2022.0105) mini_portile2 (2.8.0) minitest (5.16.3) - msgpack (1.5.6) + msgpack (1.6.0) mustache (1.1.1) net-http-digest_auth (1.4.1) net-http-persistent (4.0.1) @@ -122,7 +122,7 @@ GEM rspec-support (3.11.1) rspec-wait (0.0.9) rspec (>= 3, < 4) - rspec_junit_formatter (0.5.1) + rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) rubocop (1.35.1) json (~> 2.3) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 86b0e855a6..e4ce548e7d 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -508,18 +508,9 @@ else : "${HOMEBREW_OS_VERSION:=$(uname -r)}" HOMEBREW_OS_USER_AGENT_VERSION="${HOMEBREW_OS_VERSION}" - # This is set by the user environment. - # shellcheck disable=SC2154 - if [[ -n "${HOMEBREW_ON_DEBIAN7}" ]] - then - # Special version for our debian 7 docker container used to build binutils - HOMEBREW_MINIMUM_CURL_VERSION="7.25.0" - HOMEBREW_SYSTEM_CA_CERTIFICATES_TOO_OLD="1" - HOMEBREW_FORCE_BREWED_CA_CERTIFICATES="1" - else - # Ensure the system Curl is a version that supports modern HTTPS certificates. - HOMEBREW_MINIMUM_CURL_VERSION="7.41.0" - fi + # Ensure the system Curl is a version that supports modern HTTPS certificates. + HOMEBREW_MINIMUM_CURL_VERSION="7.41.0" + curl_version_output="$(${HOMEBREW_CURL} --version 2>/dev/null)" curl_name_and_version="${curl_version_output%% (*}" # shellcheck disable=SC2248 diff --git a/Library/Homebrew/cask/cmd/install.rb b/Library/Homebrew/cask/cmd/install.rb index 69bd9d80fa..8b088de6b3 100644 --- a/Library/Homebrew/cask/cmd/install.rb +++ b/Library/Homebrew/cask/cmd/install.rb @@ -56,7 +56,8 @@ module Cask require_sha: nil, quarantine: nil, quiet: nil, - zap: nil + zap: nil, + dry_run: nil ) odie "Installing casks is supported only on macOS" unless OS.mac? @@ -73,6 +74,27 @@ module Cask options[:quarantine] = true if options[:quarantine].nil? + if dry_run + if (casks_to_install = casks.reject(&:installed?).presence) + plural = "cask".pluralize(casks_to_install.count) + ohai "Would install #{casks_to_install.count} #{plural}:" + puts casks_to_install.map(&:full_name).join(" ") + end + casks.each do |cask| + dep_names = CaskDependent.new(cask) + .runtime_dependencies + .reject(&:installed?) + .map(&:to_formula) + .map(&:name) + next if dep_names.blank? + + plural = "dependency".pluralize(dep_names.count) + ohai "Would install #{dep_names.count} #{plural} for #{cask.full_name}:" + puts dep_names.join(" ") + end + return + end + require "cask/installer" casks.each do |cask| diff --git a/Library/Homebrew/cli/args.rbi b/Library/Homebrew/cli/args.rbi index 39bb3768e7..cf4265879b 100644 --- a/Library/Homebrew/cli/args.rbi +++ b/Library/Homebrew/cli/args.rbi @@ -30,6 +30,9 @@ module Homebrew sig { returns(T::Boolean) } def newer_only?; end + sig { returns(T::Boolean) } + def resources?; end + sig { returns(T::Boolean) } def full_name?; end diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index a312190440..60f2733cd1 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -45,6 +45,8 @@ module Homebrew "(binaries and symlinks are excluded, unless originally from the same cask)." switch "-v", "--verbose", description: "Print the verification and postinstall steps." + switch "-n", "--dry-run", + description: "Show what would be installed, but do not actually install anything." [ [:switch, "--formula", "--formulae", { description: "Treat all named arguments as formulae.", @@ -193,6 +195,7 @@ module Homebrew skip_cask_deps: args.skip_cask_deps?, quarantine: args.quarantine?, quiet: args.quiet?, + dry_run: args.dry_run?, ) end @@ -242,6 +245,7 @@ module Homebrew debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?, + dry_run: args.dry_run?, ) Upgrade.check_installed_dependents( @@ -257,9 +261,10 @@ module Homebrew debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?, + dry_run: args.dry_run?, ) - Cleanup.periodic_clean! + Cleanup.periodic_clean!(dry_run: args.dry_run?) Homebrew.messages.display_messages(display_times: args.display_times?) rescue FormulaUnreadableError, FormulaClassUnavailableError, diff --git a/Library/Homebrew/dev-cmd/bump-cask-pr.rb b/Library/Homebrew/dev-cmd/bump-cask-pr.rb index 0bb1d7a821..dd697a490f 100644 --- a/Library/Homebrew/dev-cmd/bump-cask-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-cask-pr.rb @@ -188,19 +188,6 @@ module Homebrew GitHub.create_bump_pr(pr_info, args: args) end - def fetch_cask(contents, config: nil) - cask = Cask::CaskLoader.load(contents) - cask.config = config if config.present? - old_hash = cask.sha256.to_s - - cask_download = Cask::Download.new(cask, quarantine: true) - download = cask_download.fetch(verify_download_integrity: false) - Utils::Tar.validate_file(download) - new_hash = download.sha256 - - [old_hash, new_hash] - end - def check_open_pull_requests(cask, args:) tap_remote_repo = cask.tap.remote_repo || cask.tap.full_name GitHub.check_for_duplicate_pull_requests(cask.token, tap_remote_repo, diff --git a/Library/Homebrew/dev-cmd/bump.rb b/Library/Homebrew/dev-cmd/bump.rb index 009865c85d..0bc0bbc96a 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -72,17 +72,18 @@ module Homebrew ambiguous_casks = [] if !args.formula? && !args.cask? - ambiguous_casks = formulae_and_casks.group_by { |item| Livecheck.formula_or_cask_name(item, full_name: true) } - .values - .select { |items| items.length > 1 } - .flatten - .select { |item| item.is_a?(Cask::Cask) } + ambiguous_casks = formulae_and_casks \ + .group_by { |item| Livecheck.package_or_resource_name(item, full_name: true) } + .values + .select { |items| items.length > 1 } + .flatten + .select { |item| item.is_a?(Cask::Cask) } end ambiguous_names = [] unless args.full_name? ambiguous_names = - (formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.formula_or_cask_name(item) } + (formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.package_or_resource_name(item) } .values .select { |items| items.length > 1 } .flatten @@ -92,7 +93,7 @@ module Homebrew puts if i.positive? use_full_name = args.full_name? || ambiguous_names.include?(formula_or_cask) - name = Livecheck.formula_or_cask_name(formula_or_cask, full_name: use_full_name) + name = Livecheck.package_or_resource_name(formula_or_cask, full_name: use_full_name) repository = if formula_or_cask.is_a?(Formula) if formula_or_cask.head_only? ohai name @@ -157,7 +158,7 @@ module Homebrew rescue next end - name = Livecheck.formula_or_cask_name(formula_or_cask) + name = Livecheck.package_or_resource_name(formula_or_cask) ambiguous_cask = begin formula_or_cask.is_a?(Cask::Cask) && !args.cask? && Formula[name] rescue FormulaUnavailableError @@ -178,7 +179,7 @@ module Homebrew end def livecheck_result(formula_or_cask) - name = Livecheck.formula_or_cask_name(formula_or_cask) + name = Livecheck.package_or_resource_name(formula_or_cask) referenced_formula_or_cask, = Livecheck.resolve_livecheck_reference(formula_or_cask, full_name: false, debug: false) diff --git a/Library/Homebrew/dev-cmd/livecheck.rb b/Library/Homebrew/dev-cmd/livecheck.rb index bd65c29f6a..3b87f7bf13 100644 --- a/Library/Homebrew/dev-cmd/livecheck.rb +++ b/Library/Homebrew/dev-cmd/livecheck.rb @@ -37,6 +37,8 @@ module Homebrew description: "Show the latest version only if it's newer than the formula/cask." switch "--json", description: "Output information in JSON format." + switch "-r", "--resources", + description: "Also check resources for formulae." switch "-q", "--quiet", description: "Suppress warnings, don't print a progress bar for JSON output." switch "--formula", "--formulae", @@ -101,6 +103,7 @@ module Homebrew else raise UsageError, "A watchlist file is required when no arguments are given." end + formulae_and_casks_to_check = formulae_and_casks_to_check.sort_by do |formula_or_cask| formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name end @@ -111,6 +114,7 @@ module Homebrew json: args.json?, full_name: args.full_name?, handle_name_conflict: !args.formula? && !args.cask?, + check_resources: args.resources?, newer_only: args.newer_only?, quiet: args.quiet?, debug: args.debug?, diff --git a/Library/Homebrew/extend/os/linux/linkage_checker.rb b/Library/Homebrew/extend/os/linux/linkage_checker.rb index b708cf23a9..2f672353d3 100644 --- a/Library/Homebrew/extend/os/linux/linkage_checker.rb +++ b/Library/Homebrew/extend/os/linux/linkage_checker.rb @@ -7,6 +7,7 @@ class LinkageChecker # Libraries provided by glibc and gcc. SYSTEM_LIBRARY_ALLOWLIST = %w[ ld-linux-x86-64.so.2 + ld-linux-aarch64.so.1 libanl.so.1 libatomic.so.1 libc.so.6 diff --git a/Library/Homebrew/hardware.rb b/Library/Homebrew/hardware.rb index 52bf2e5e88..804085f0e8 100644 --- a/Library/Homebrew/hardware.rb +++ b/Library/Homebrew/hardware.rb @@ -11,7 +11,7 @@ module Hardware INTEL_64BIT_ARCHS = [:x86_64].freeze PPC_32BIT_ARCHS = [:ppc, :ppc32, :ppc7400, :ppc7450, :ppc970].freeze PPC_64BIT_ARCHS = [:ppc64, :ppc64le, :ppc970].freeze - ARM_64BIT_ARCHS = [:arm64].freeze + ARM_64BIT_ARCHS = [:arm64, :aarch64].freeze ALL_ARCHS = [ *INTEL_32BIT_ARCHS, *INTEL_64BIT_ARCHS, diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb index be0467fa23..86e0f7c5b6 100644 --- a/Library/Homebrew/install.rb +++ b/Library/Homebrew/install.rb @@ -278,10 +278,11 @@ module Homebrew overwrite: false, debug: false, quiet: false, - verbose: false + verbose: false, + dry_run: false ) formula_installers = formulae_to_install.map do |f| - Migrator.migrate_if_needed(f, force: force) + Migrator.migrate_if_needed(f, force: force, dry_run: dry_run) build_options = f.build fi = FormulaInstaller.new( @@ -307,8 +308,10 @@ module Homebrew ) begin - fi.prelude - fi.fetch + unless dry_run + fi.prelude + fi.fetch + end fi rescue CannotInstallFormulaError => e ofail e.message @@ -319,6 +322,20 @@ module Homebrew end end.compact + if dry_run + if (formulae_name_to_install = formulae_to_install.map(&:name)) + plural = "formula".pluralize(formulae_name_to_install.count) + ohai "Would install #{formulae_name_to_install.count} #{plural}:" + puts formulae_name_to_install.join(" ") + + formula_installers.each do |fi| + f = fi.formula + print_dry_run_dependencies(f, fi.compute_dependencies, &:name) + end + end + return + end + formula_installers.each do |fi| install_formula(fi) Cleanup.install_formula_clean!(fi.formula) @@ -333,6 +350,15 @@ module Homebrew Upgrade.install_formula(formula_installer, upgrade: upgrade) end private_class_method :install_formula + + def print_dry_run_dependencies(formula, dependencies, &block) + return if dependencies.empty? + + plural = "dependency".pluralize(dependencies.count) + ohai "Would install #{dependencies.count} #{plural} for #{formula.name}:" + formula_names = dependencies.map(&:first).map(&:to_formula).map(&block) + puts formula_names.join(" ") + end end end diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index bdc25c3371..f4ae28f06a 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -126,11 +126,11 @@ module Homebrew if debug # Print the chain of references for debugging puts "Reference Chain:" - puts formula_or_cask_name(first_formula_or_cask, full_name: full_name) + puts package_or_resource_name(first_formula_or_cask, full_name: full_name) references << referenced_formula_or_cask references.each do |ref_formula_or_cask| - puts formula_or_cask_name(ref_formula_or_cask, full_name: full_name) + puts package_or_resource_name(ref_formula_or_cask, full_name: full_name) end end @@ -157,11 +157,14 @@ module Homebrew # Executes the livecheck logic for each formula/cask in the # `formulae_and_casks_to_check` array and prints the results. + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/PerceivedComplexity sig { params( formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)], full_name: T::Boolean, handle_name_conflict: T::Boolean, + check_resources: T::Boolean, json: T::Boolean, newer_only: T::Boolean, debug: T::Boolean, @@ -171,24 +174,25 @@ module Homebrew } def run_checks( formulae_and_casks_to_check, - full_name: false, handle_name_conflict: false, json: false, newer_only: false, + full_name: false, handle_name_conflict: false, check_resources: false, json: false, newer_only: false, debug: false, quiet: false, verbose: false ) load_other_tap_strategies(formulae_and_casks_to_check) ambiguous_casks = [] if handle_name_conflict - ambiguous_casks = formulae_and_casks_to_check.group_by { |item| formula_or_cask_name(item, full_name: true) } - .values - .select { |items| items.length > 1 } - .flatten - .select { |item| item.is_a?(Cask::Cask) } + ambiguous_casks = formulae_and_casks_to_check \ + .group_by { |item| package_or_resource_name(item, full_name: true) } + .values + .select { |items| items.length > 1 } + .flatten + .select { |item| item.is_a?(Cask::Cask) } end ambiguous_names = [] unless full_name ambiguous_names = - (formulae_and_casks_to_check - ambiguous_casks).group_by { |item| formula_or_cask_name(item) } + (formulae_and_casks_to_check - ambiguous_casks).group_by { |item| package_or_resource_name(item) } .values .select { |items| items.length > 1 } .flatten @@ -218,7 +222,7 @@ module Homebrew cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) use_full_name = full_name || ambiguous_names.include?(formula_or_cask) - name = formula_or_cask_name(formula_or_cask, full_name: use_full_name) + name = package_or_resource_name(formula_or_cask, full_name: use_full_name) referenced_formula_or_cask, livecheck_references = resolve_livecheck_reference(formula_or_cask, full_name: use_full_name, debug: debug) @@ -282,6 +286,30 @@ module Homebrew version_info[:latest] if version_info.present? end + check_for_resources = check_resources && formula_or_cask.is_a?(Formula) && formula_or_cask.resources.present? + if check_for_resources + resource_version_info = formula_or_cask.resources.map do |resource| + res_skip_info ||= SkipConditions.skip_information(resource, verbose: verbose) + if res_skip_info.present? + res_skip_info + else + res_version_info = resource_version( + resource, + json: json, + debug: debug, + quiet: quiet, + verbose: verbose, + ) + if res_version_info.empty? + status_hash(resource, "error", ["Unable to get versions"], verbose: verbose) + else + res_version_info + end + end + end.compact_blank + Homebrew.failed = true if resource_version_info.any? { |info| info[:status] == "error" } + end + if latest.blank? no_versions_msg = "Unable to get versions" raise Livecheck::Error, no_versions_msg unless json @@ -289,7 +317,14 @@ module Homebrew next version_info if version_info.is_a?(Hash) && version_info[:status] && version_info[:messages] - next status_hash(formula_or_cask, "error", [no_versions_msg], full_name: use_full_name, verbose: verbose) + latest_info = status_hash(formula_or_cask, "error", [no_versions_msg], full_name: use_full_name, + verbose: verbose) + if check_for_resources + resource_version_info.map! { |r| r.except!(:meta) } unless verbose + latest_info[:resources] = resource_version_info + end + + next latest_info end if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/) @@ -324,6 +359,8 @@ module Homebrew info[:meta][:head_only] = true if formula&.head_only? info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta) + info[:resources] = resource_version_info if check_for_resources + next if newer_only && !info[:version][:outdated] has_a_newer_upstream_version ||= true @@ -331,10 +368,12 @@ module Homebrew if json progress&.increment info.except!(:meta) unless verbose + resource_version_info.map! { |r| r.except!(:meta) } if check_for_resources && !verbose next info end - + puts if debug print_latest_version(info, verbose: verbose, ambiguous_cask: ambiguous_casks.include?(formula_or_cask)) + print_resources_info(resource_version_info, verbose: verbose) if check_for_resources nil rescue => e Homebrew.failed = true @@ -344,11 +383,12 @@ module Homebrew progress&.increment status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name, verbose: verbose) unless quiet elsif !quiet - name = formula_or_cask_name(formula_or_cask, full_name: use_full_name) + name = package_or_resource_name(formula_or_cask, full_name: use_full_name) name += " (cask)" if ambiguous_casks.include?(formula_or_cask) onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}" $stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error) + print_resources_info(resource_version_info, verbose: verbose) if check_for_resources nil end end @@ -367,16 +407,20 @@ module Homebrew puts JSON.pretty_generate(formulae_checked.compact) end + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity - sig { params(formula_or_cask: T.any(Formula, Cask::Cask), full_name: T::Boolean).returns(String) } - def formula_or_cask_name(formula_or_cask, full_name: false) - case formula_or_cask + sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource), full_name: T::Boolean).returns(String) } + def package_or_resource_name(package_or_resource, full_name: false) + case package_or_resource when Formula - formula_name(formula_or_cask, full_name: full_name) + formula_name(package_or_resource, full_name: full_name) when Cask::Cask - cask_name(formula_or_cask, full_name: full_name) + cask_name(package_or_resource, full_name: full_name) + when Resource + package_or_resource.name else - T.absurd(formula_or_cask) + T.absurd(package_or_resource) end end @@ -396,40 +440,44 @@ module Homebrew sig { params( - formula_or_cask: T.any(Formula, Cask::Cask), - status_str: String, - messages: T.nilable(T::Array[String]), - full_name: T::Boolean, - verbose: T::Boolean, + package_or_resource: T.any(Formula, Cask::Cask, Resource), + status_str: String, + messages: T.nilable(T::Array[String]), + full_name: T::Boolean, + verbose: T::Boolean, ).returns(Hash) } - def status_hash(formula_or_cask, status_str, messages = nil, full_name: false, verbose: false) - formula = formula_or_cask if formula_or_cask.is_a?(Formula) - cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) + def status_hash(package_or_resource, status_str, messages = nil, full_name: false, verbose: false) + formula = package_or_resource if package_or_resource.is_a?(Formula) + cask = package_or_resource if package_or_resource.is_a?(Cask::Cask) + resource = package_or_resource if package_or_resource.is_a?(Resource) status_hash = {} if formula status_hash[:formula] = formula_name(formula, full_name: full_name) elsif cask - status_hash[:cask] = cask_name(formula_or_cask, full_name: full_name) + status_hash[:cask] = cask_name(cask, full_name: full_name) + elsif resource + status_hash[:resource] = resource.name end status_hash[:status] = status_str status_hash[:messages] = messages if messages.is_a?(Array) status_hash[:meta] = { - livecheckable: formula_or_cask.livecheckable?, + livecheckable: package_or_resource.livecheckable?, } status_hash[:meta][:head_only] = true if formula&.head_only? status_hash end - # Formats and prints the livecheck result for a formula. + # Formats and prints the livecheck result for a formula/cask/resource. sig { params(info: Hash, verbose: T::Boolean, ambiguous_cask: T::Boolean).void } - def print_latest_version(info, verbose:, ambiguous_cask: false) - formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}" - formula_or_cask_s += " (cask)" if ambiguous_cask - formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && verbose + def print_latest_version(info, verbose: false, ambiguous_cask: false) + package_or_resource_s = info[:resource].present? ? " " : "" + package_or_resource_s += "#{Tty.blue}#{info[:formula] || info[:cask] || info[:resource]}#{Tty.reset}" + package_or_resource_s += " (cask)" if ambiguous_cask + package_or_resource_s += " (guessed)" if verbose && !info[:meta][:livecheckable] current_s = if info[:version][:newer_than_upstream] "#{Tty.red}#{info[:version][:current]}#{Tty.reset}" @@ -443,47 +491,61 @@ module Homebrew info[:version][:latest] end - puts "#{formula_or_cask_s}: #{current_s} ==> #{latest_s}" + puts "#{package_or_resource_s}: #{current_s} ==> #{latest_s}" + end + + # Prints the livecheck result for the resources of a given Formula. + sig { params(info: T::Array[Hash], verbose: T::Boolean).void } + def print_resources_info(info, verbose: false) + info.each do |r_info| + if r_info[:status] && r_info[:messages] + SkipConditions.print_skip_information(r_info) + else + print_latest_version(r_info, verbose: verbose) + end + end end sig { params( - livecheck_url: T.any(String, Symbol), - formula_or_cask: T.any(Formula, Cask::Cask), + livecheck_url: T.any(String, Symbol), + package_or_resource: T.any(Formula, Cask::Cask, Resource), ).returns(T.nilable(String)) } - def livecheck_url_to_string(livecheck_url, formula_or_cask) + def livecheck_url_to_string(livecheck_url, package_or_resource) case livecheck_url when String livecheck_url when :url - formula_or_cask.url&.to_s if formula_or_cask.is_a?(Cask::Cask) + package_or_resource.url&.to_s if package_or_resource.is_a?(Cask::Cask) || package_or_resource.is_a?(Resource) when :head, :stable - formula_or_cask.send(livecheck_url)&.url if formula_or_cask.is_a?(Formula) + package_or_resource.send(livecheck_url)&.url if package_or_resource.is_a?(Formula) when :homepage - formula_or_cask.homepage + package_or_resource.homepage unless package_or_resource.is_a?(Resource) end end - # Returns an Array containing the formula/cask URLs that can be used by livecheck. - sig { params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T::Array[String]) } - def checkable_urls(formula_or_cask) + # Returns an Array containing the formula/cask/resource URLs that can be used by livecheck. + sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource)).returns(T::Array[String]) } + def checkable_urls(package_or_resource) urls = [] - case formula_or_cask + case package_or_resource when Formula - if formula_or_cask.stable - urls << formula_or_cask.stable.url - urls.concat(formula_or_cask.stable.mirrors) + if package_or_resource.stable + urls << package_or_resource.stable.url + urls.concat(package_or_resource.stable.mirrors) end - urls << formula_or_cask.head.url if formula_or_cask.head - urls << formula_or_cask.homepage if formula_or_cask.homepage + urls << package_or_resource.head.url if package_or_resource.head + urls << package_or_resource.homepage if package_or_resource.homepage when Cask::Cask - urls << formula_or_cask.appcast.to_s if formula_or_cask.appcast - urls << formula_or_cask.url.to_s if formula_or_cask.url - urls << formula_or_cask.homepage if formula_or_cask.homepage + urls << package_or_resource.appcast.to_s if package_or_resource.appcast + urls << package_or_resource.url.to_s if package_or_resource.url + urls << package_or_resource.homepage if package_or_resource.homepage + when Resource + urls << package_or_resource.url else - T.absurd(formula_or_cask) + T.absurd(package_or_resource) end urls.compact.uniq @@ -561,7 +623,7 @@ module Homebrew homebrew_curl_root_domains.include?(url_root_domain) end - # Identifies the latest version of the formula and returns a Hash containing + # Identifies the latest version of the formula/cask and returns a Hash containing # the version information. Returns nil if a latest version couldn't be found. # rubocop:disable Metrics/CyclomaticComplexity sig { @@ -713,7 +775,6 @@ module Homebrew version.to_s.include?(rejection) end end - next if match_version_map.blank? if debug @@ -770,6 +831,195 @@ module Homebrew nil end # rubocop:enable Metrics/CyclomaticComplexity + + # Identifies the latest version of a resource and returns a Hash containing the + # version information. Returns nil if a latest version couldn't be found. + sig { + params( + resource: Resource, + json: T::Boolean, + debug: T::Boolean, + quiet: T::Boolean, + verbose: T::Boolean, + ).returns(Hash) + } + def resource_version( + resource, + json: false, + debug: false, + quiet: false, + verbose: false + ) + has_livecheckable = resource.livecheckable? + + if debug + puts "\n\n" + puts "Resource: #{resource.name}" + puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}" + end + + resource_version_info = {} + + livecheck = resource.livecheck + livecheck_url = livecheck.url + livecheck_regex = livecheck.regex + livecheck_strategy = livecheck.strategy + livecheck_strategy_block = livecheck.strategy_block + + livecheck_url_string = livecheck_url_to_string(livecheck_url, resource) + + urls = [livecheck_url_string] if livecheck_url_string + urls ||= checkable_urls(resource) + + checked_urls = [] + # rubocop:disable Metrics/BlockLength + urls.each_with_index do |original_url, i| + # Only preprocess the URL when it's appropriate + url = if STRATEGY_SYMBOLS_TO_SKIP_PREPROCESS_URL.include?(livecheck_strategy) + original_url + else + preprocess_url(original_url) + end + next if checked_urls.include?(url) + + strategies = Strategy.from_url( + url, + livecheck_strategy: livecheck_strategy, + url_provided: livecheck_url.present?, + regex_provided: livecheck_regex.present?, + block_provided: livecheck_strategy_block.present?, + ) + strategy = Strategy.from_symbol(livecheck_strategy) || strategies.first + strategy_name = livecheck_strategy_names[strategy] + + if debug + puts + if livecheck_url.is_a?(Symbol) + # This assumes the URL symbol will fit within the available space + puts "URL (#{livecheck_url}):".ljust(18, " ") + original_url + else + puts "URL: #{original_url}" + end + puts "URL (processed): #{url}" if url != original_url + if strategies.present? && verbose + puts "Strategies: #{strategies.map { |s| livecheck_strategy_names[s] }.join(", ")}" + end + puts "Strategy: #{strategy.blank? ? "None" : strategy_name}" + puts "Regex: #{livecheck_regex.inspect}" if livecheck_regex.present? + end + + if livecheck_strategy.present? + if livecheck_url.blank? && strategy.method(:find_versions).parameters.include?([:keyreq, :url]) + odebug "#{strategy_name} strategy requires a URL" + next + elsif livecheck_strategy != :page_match && strategies.exclude?(strategy) + odebug "#{strategy_name} strategy does not apply to this URL" + next + end + end + puts if debug && strategy.blank? + next if strategy.blank? + + strategy_data = strategy.find_versions( + url: url, + regex: livecheck_regex, + homebrew_curl: false, + &livecheck_strategy_block + ) + match_version_map = strategy_data[:matches] + regex = strategy_data[:regex] + messages = strategy_data[:messages] + checked_urls << url + + if messages.is_a?(Array) && match_version_map.blank? + puts messages unless json + next if i + 1 < urls.length + + return status_hash(resource, "error", messages, verbose: verbose) + end + + if debug + if strategy_data[:url].present? && strategy_data[:url] != url + puts "URL (strategy): #{strategy_data[:url]}" + end + puts "URL (final): #{strategy_data[:final_url]}" if strategy_data[:final_url].present? + if strategy_data[:regex].present? && strategy_data[:regex] != livecheck_regex + puts "Regex (strategy): #{strategy_data[:regex].inspect}" + end + puts "Cached?: Yes" if strategy_data[:cached] == true + end + + match_version_map.delete_if do |_match, version| + next true if version.blank? + next false if has_livecheckable + + UNSTABLE_VERSION_KEYWORDS.any? do |rejection| + version.to_s.include?(rejection) + end + end + next if match_version_map.blank? + + if debug + puts + puts "Matched Versions:" + + if verbose + match_version_map.each do |match, version| + puts "#{match} => #{version.inspect}" + end + else + puts match_version_map.values.join(", ") + end + end + + res_current = resource.version + res_latest = Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(resource, v) }) + + return status_hash(resource, "error", ["Unable to get versions"], verbose: verbose) if res_latest.blank? + + is_outdated = res_current < res_latest + is_newer_than_upstream = res_current > res_latest + + resource_version_info = { + resource: resource.name, + version: { + current: res_current.to_s, + latest: res_latest.to_s, + outdated: is_outdated, + newer_than_upstream: is_newer_than_upstream, + }, + } + + resource_version_info[:meta] = { livecheckable: has_livecheckable, url: {} } + if livecheck_url.is_a?(Symbol) && livecheck_url_string + resource_version_info[:meta][:url][:symbol] = livecheck_url + end + resource_version_info[:meta][:url][:original] = original_url + resource_version_info[:meta][:url][:processed] = url if url != original_url + if strategy_data[:url].present? && strategy_data[:url] != url + resource_version_info[:meta][:url][:strategy] = strategy_data[:url] + end + resource_version_info[:meta][:url][:final] = strategy_data[:final_url] if strategy_data[:final_url] + resource_version_info[:meta][:strategy] = strategy.present? ? strategy_name : nil + if strategies.present? + resource_version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names[s] } + end + resource_version_info[:meta][:regex] = regex.inspect if regex.present? + resource_version_info[:meta][:cached] = true if strategy_data[:cached] == true + + rescue => e + Homebrew.failed = true + if json + status_hash(resource, "error", [e.to_s], verbose: verbose) + elsif !quiet + onoe "#{Tty.blue}#{resource.name}#{Tty.reset}: #{e}" + $stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error) + nil + end + end + # rubocop:enable Metrics/BlockLength + resource_version_info + end end # rubocop:enable Metrics/ModuleLength end diff --git a/Library/Homebrew/livecheck/livecheck_version.rb b/Library/Homebrew/livecheck/livecheck_version.rb index 80336076e7..ba557cf4ad 100644 --- a/Library/Homebrew/livecheck/livecheck_version.rb +++ b/Library/Homebrew/livecheck/livecheck_version.rb @@ -11,15 +11,17 @@ module Homebrew include Comparable - sig { params(formula_or_cask: T.any(Formula, Cask::Cask), version: Version).returns(LivecheckVersion) } - def self.create(formula_or_cask, version) - versions = case formula_or_cask - when Formula + sig { + params(package_or_resource: T.any(Formula, Cask::Cask, Resource), version: Version).returns(LivecheckVersion) + } + def self.create(package_or_resource, version) + versions = case package_or_resource + when Formula, Resource [version] when Cask::Cask version.to_s.split(/[,:]/).map { |s| Version.new(s) } else - T.absurd(formula_or_cask) + T.absurd(package_or_resource) end new(versions) end diff --git a/Library/Homebrew/livecheck/skip_conditions.rb b/Library/Homebrew/livecheck/skip_conditions.rb index f5d2f08358..be5159cb97 100644 --- a/Library/Homebrew/livecheck/skip_conditions.rb +++ b/Library/Homebrew/livecheck/skip_conditions.rb @@ -6,7 +6,7 @@ require "livecheck/livecheck" module Homebrew module Livecheck # The `Livecheck::SkipConditions` module primarily contains methods that - # check for various formula/cask conditions where a check should be skipped. + # check for various formula/cask/resource conditions where a check should be skipped. # # @api private module SkipConditions @@ -16,14 +16,14 @@ module Homebrew sig { params( - formula_or_cask: T.any(Formula, Cask::Cask), - livecheckable: T::Boolean, - full_name: T::Boolean, - verbose: T::Boolean, + package_or_resource: T.any(Formula, Cask::Cask, Resource), + livecheckable: T::Boolean, + full_name: T::Boolean, + verbose: T::Boolean, ).returns(Hash) } - def formula_or_cask_skip(formula_or_cask, livecheckable, full_name: false, verbose: false) - formula = formula_or_cask if formula_or_cask.is_a?(Formula) + def package_or_resource_skip(package_or_resource, livecheckable, full_name: false, verbose: false) + formula = package_or_resource if package_or_resource.is_a?(Formula) if (stable_url = formula&.stable&.url) stable_is_gist = stable_url.match?(%r{https?://gist\.github(?:usercontent)?\.com/}i) @@ -33,8 +33,8 @@ module Homebrew stable_from_internet_archive = stable_url.match?(%r{https?://web\.archive\.org/}i) end - skip_message = if formula_or_cask.livecheck.skip_msg.present? - formula_or_cask.livecheck.skip_msg + skip_message = if package_or_resource.livecheck.skip_msg.present? + package_or_resource.livecheck.skip_msg elsif !livecheckable if stable_from_google_code_archive "Stable URL is from Google Code Archive" @@ -45,10 +45,10 @@ module Homebrew end end - return {} if !formula_or_cask.livecheck.skip? && skip_message.blank? + return {} if !package_or_resource.livecheck.skip? && skip_message.blank? skip_messages = skip_message ? [skip_message] : nil - Livecheck.status_hash(formula_or_cask, "skipped", skip_messages, full_name: full_name, verbose: verbose) + Livecheck.status_hash(package_or_resource, "skipped", skip_messages, full_name: full_name, verbose: verbose) end sig { @@ -157,7 +157,7 @@ module Homebrew # Skip conditions for formulae. FORMULA_CHECKS = [ - :formula_or_cask_skip, + :package_or_resource_skip, :formula_head_only, :formula_deprecated, :formula_disabled, @@ -166,76 +166,85 @@ module Homebrew # Skip conditions for casks. CASK_CHECKS = [ - :formula_or_cask_skip, + :package_or_resource_skip, :cask_discontinued, :cask_version_latest, :cask_url_unversioned, ].freeze - # If a formula/cask should be skipped, we return a hash from + # Skip conditions for resources. + RESOURCE_CHECKS = [ + :package_or_resource_skip, + ].freeze + + # If a formula/cask/resource should be skipped, we return a hash from # `Livecheck#status_hash`, which contains a `status` type and sometimes # error `messages`. sig { params( - formula_or_cask: T.any(Formula, Cask::Cask), - full_name: T::Boolean, - verbose: T::Boolean, + package_or_resource: T.any(Formula, Cask::Cask, Resource), + full_name: T::Boolean, + verbose: T::Boolean, ).returns(Hash) } - def skip_information(formula_or_cask, full_name: false, verbose: false) - livecheckable = formula_or_cask.livecheckable? + def skip_information(package_or_resource, full_name: false, verbose: false) + livecheckable = package_or_resource.livecheckable? - checks = case formula_or_cask + checks = case package_or_resource when Formula FORMULA_CHECKS when Cask::Cask CASK_CHECKS + when Resource + RESOURCE_CHECKS end return {} unless checks checks.each do |method_name| - skip_hash = send(method_name, formula_or_cask, livecheckable, full_name: full_name, verbose: verbose) + skip_hash = send(method_name, package_or_resource, livecheckable, full_name: full_name, verbose: verbose) return skip_hash if skip_hash.present? end {} end - # Skip conditions for formulae/casks referenced in a `livecheck` block + # Skip conditions for formulae/casks/resources referenced in a `livecheck` block # are treated differently than normal. We only respect certain skip # conditions (returning the related hash) and others are treated as # errors. sig { params( - livecheck_formula_or_cask: T.any(Formula, Cask::Cask), - original_formula_or_cask_name: String, - full_name: T::Boolean, - verbose: T::Boolean, + livecheck_package_or_resource: T.any(Formula, Cask::Cask, Resource), + original_package_or_resource_name: String, + full_name: T::Boolean, + verbose: T::Boolean, ).returns(T.nilable(Hash)) } def referenced_skip_information( - livecheck_formula_or_cask, - original_formula_or_cask_name, + livecheck_package_or_resource, + original_package_or_resource_name, full_name: false, verbose: false ) skip_info = SkipConditions.skip_information( - livecheck_formula_or_cask, + livecheck_package_or_resource, full_name: full_name, verbose: verbose, ) return if skip_info.blank? - referenced_name = Livecheck.formula_or_cask_name(livecheck_formula_or_cask, full_name: full_name) - referenced_type = case livecheck_formula_or_cask + referenced_name = Livecheck.package_or_resource_name(livecheck_package_or_resource, full_name: full_name) + referenced_type = case livecheck_package_or_resource when Formula :formula when Cask::Cask :cask + when Resource + :resource end if skip_info[:status] != "error" && - !(skip_info[:status] == "skipped" && livecheck_formula_or_cask.livecheck.skip?) + !(skip_info[:status] == "skipped" && livecheck_package_or_resource.livecheck.skip?) error_msg_end = if skip_info[:status] == "skipped" "automatically skipped" else @@ -245,7 +254,7 @@ module Homebrew raise "Referenced #{referenced_type} (#{referenced_name}) is #{error_msg_end}" end - skip_info[referenced_type] = original_formula_or_cask_name + skip_info[referenced_type] = original_package_or_resource_name skip_info end @@ -258,6 +267,8 @@ module Homebrew skip_hash[:formula] elsif skip_hash[:cask].is_a?(String) skip_hash[:cask] + elsif skip_hash[:resource].is_a?(String) + " #{skip_hash[:resource]}" end return unless name diff --git a/Library/Homebrew/sorbet/rbi/gems/msgpack@1.5.6.rbi b/Library/Homebrew/sorbet/rbi/gems/msgpack@1.6.0.rbi similarity index 100% rename from Library/Homebrew/sorbet/rbi/gems/msgpack@1.5.6.rbi rename to Library/Homebrew/sorbet/rbi/gems/msgpack@1.6.0.rbi diff --git a/Library/Homebrew/sorbet/rbi/gems/rspec_junit_formatter@0.5.1.rbi b/Library/Homebrew/sorbet/rbi/gems/rspec_junit_formatter@0.6.0.rbi similarity index 100% rename from Library/Homebrew/sorbet/rbi/gems/rspec_junit_formatter@0.5.1.rbi rename to Library/Homebrew/sorbet/rbi/gems/rspec_junit_formatter@0.6.0.rbi diff --git a/Library/Homebrew/test/livecheck/livecheck_spec.rb b/Library/Homebrew/test/livecheck/livecheck_spec.rb index 02ba9f58eb..c23f2391b9 100644 --- a/Library/Homebrew/test/livecheck/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck/livecheck_spec.rb @@ -11,6 +11,7 @@ describe Homebrew::Livecheck do let(:homepage_url) { "https://brew.sh" } let(:livecheck_url) { "https://formulae.brew.sh/api/formula/ruby.json" } let(:stable_url) { "https://brew.sh/test-0.0.1.tgz" } + let(:resource_url) { "https://brew.sh/foo-1.0.tar.gz" } let(:f) do formula("test") do @@ -23,9 +24,21 @@ describe Homebrew::Livecheck do url "https://formulae.brew.sh/api/formula/ruby.json" regex(/"stable":"(\d+(?:\.\d+)+)"/i) end + + resource "foo" do + url "https://brew.sh/foo-1.0.tar.gz" + sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + + livecheck do + url "https://brew.sh/test/releases" + regex(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i) + end + end end end + let(:r) { f.resources.first } + let(:c) do Cask::CaskLoader.load(+<<-RUBY) cask "test" do @@ -44,15 +57,6 @@ describe Homebrew::Livecheck do RUBY end - let(:f_duplicate_urls) do - formula("test_duplicate_urls") do - desc "Test formula with a duplicate URL" - homepage "https://github.com/Homebrew/brew.git" - url "https://brew.sh/test-0.0.1.tgz" - head "https://github.com/Homebrew/brew.git" - end - end - describe "::resolve_livecheck_reference" do context "when a formula/cask has a livecheck block without formula/cask methods" do it "returns [nil, []]" do @@ -83,7 +87,7 @@ describe Homebrew::Livecheck do end describe "::status_hash" do - it "returns a hash containing the livecheck status" do + it "returns a hash containing the livecheck status for a formula" do expect(livecheck.status_hash(f, "error", ["Unable to get versions"])) .to eq({ formula: "test", @@ -94,6 +98,18 @@ describe Homebrew::Livecheck do }, }) end + + it "returns a hash containing the livecheck status for a resource" do + expect(livecheck.status_hash(r, "error", ["Unable to get versions"])) + .to eq({ + resource: "foo", + status: "error", + messages: ["Unable to get versions"], + meta: { + livecheckable: true, + }, + }) + end end describe "::livecheck_url_to_string" do @@ -101,15 +117,28 @@ describe Homebrew::Livecheck do homepage_url_s = homepage_url stable_url_s = stable_url head_url_s = head_url + resource_url_s = resource_url formula("test_livecheck_url") do desc "Test Livecheck URL formula" homepage homepage_url_s url stable_url_s head head_url_s + + resource "foo" do + url resource_url_s + sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + + livecheck do + url "https://brew.sh/test/releases" + regex(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i) + end + end end end + let(:r_livecheck_url) { f_livecheck_url.resources.first } + let(:c_livecheck_url) do Cask::CaskLoader.load(+<<-RUBY) cask "test_livecheck_url" do @@ -123,30 +152,48 @@ describe Homebrew::Livecheck do RUBY end - it "returns a URL string when given a livecheck_url string" do + it "returns a URL string when given a livecheck_url string for a formula" do expect(livecheck.livecheck_url_to_string(livecheck_url, f_livecheck_url)).to eq(livecheck_url) end + it "returns a URL string when given a livecheck_url string for a resource" do + expect(livecheck.livecheck_url_to_string(livecheck_url, r_livecheck_url)).to eq(livecheck_url) + end + it "returns a URL symbol when given a valid livecheck_url symbol" do expect(livecheck.livecheck_url_to_string(:head, f_livecheck_url)).to eq(head_url) expect(livecheck.livecheck_url_to_string(:homepage, f_livecheck_url)).to eq(homepage_url) expect(livecheck.livecheck_url_to_string(:homepage, c_livecheck_url)).to eq(homepage_url) expect(livecheck.livecheck_url_to_string(:stable, f_livecheck_url)).to eq(stable_url) expect(livecheck.livecheck_url_to_string(:url, c_livecheck_url)).to eq(cask_url) + expect(livecheck.livecheck_url_to_string(:url, r_livecheck_url)).to eq(resource_url) end it "returns nil when not given a string or valid symbol" do expect(livecheck.livecheck_url_to_string(nil, f_livecheck_url)).to be_nil expect(livecheck.livecheck_url_to_string(nil, c_livecheck_url)).to be_nil + expect(livecheck.livecheck_url_to_string(nil, r_livecheck_url)).to be_nil expect(livecheck.livecheck_url_to_string(:invalid_symbol, f_livecheck_url)).to be_nil expect(livecheck.livecheck_url_to_string(:invalid_symbol, c_livecheck_url)).to be_nil + expect(livecheck.livecheck_url_to_string(:invalid_symbol, r_livecheck_url)).to be_nil end end describe "::checkable_urls" do + let(:resource_url) { "https://brew.sh/foo-1.0.tar.gz" } + let(:f_duplicate_urls) do + formula("test_duplicate_urls") do + desc "Test formula with a duplicate URL" + homepage "https://github.com/Homebrew/brew.git" + url "https://brew.sh/test-0.0.1.tgz" + head "https://github.com/Homebrew/brew.git" + end + end + it "returns the list of URLs to check" do expect(livecheck.checkable_urls(f)).to eq([stable_url, head_url, homepage_url]) expect(livecheck.checkable_urls(c)).to eq([cask_url, homepage_url]) + expect(livecheck.checkable_urls(r)).to eq([resource_url]) expect(livecheck.checkable_urls(f_duplicate_urls)).to eq([stable_url, head_url]) end end diff --git a/Library/Homebrew/test/livecheck/livecheck_version_spec.rb b/Library/Homebrew/test/livecheck/livecheck_version_spec.rb index 95f445cd87..14d070ba23 100644 --- a/Library/Homebrew/test/livecheck/livecheck_version_spec.rb +++ b/Library/Homebrew/test/livecheck/livecheck_version_spec.rb @@ -6,6 +6,7 @@ require "livecheck/livecheck_version" describe Homebrew::Livecheck::LivecheckVersion do let(:formula) { instance_double(Formula) } let(:cask) { instance_double(Cask::Cask) } + let(:resource) { instance_double(Resource) } before do # Case statements use #=== for case equality purposes @@ -13,6 +14,8 @@ describe Homebrew::Livecheck::LivecheckVersion do allow(Formula).to receive(:===).with(formula).and_return(true) allow(Cask::Cask).to receive(:===).and_call_original allow(Cask::Cask).to receive(:===).with(cask).and_return(true) + allow(Resource).to receive(:===).and_call_original + allow(Resource).to receive(:===).with(resource).and_return(true) end specify "::create" do @@ -28,5 +31,11 @@ describe Homebrew::Livecheck::LivecheckVersion do .to eq ["1.0", "100", "1426778671"] expect(described_class.create(cask, Version.new("0.17.0,20210111183933,226")).versions) .to eq ["0.17.0", "20210111183933", "226"] + + expect(described_class.create(resource, Version.new("1.1.6")).versions).to eq ["1.1.6"] + expect(described_class.create(resource, Version.new("2.19.0,1.8.0")).versions).to eq ["2.19.0,1.8.0"] + expect(described_class.create(resource, Version.new("1.0,100:1426778671")).versions).to eq ["1.0,100:1426778671"] + expect(described_class.create(resource, Version.new("0.17.0,20210111183933,226")).versions) + .to eq ["0.17.0,20210111183933,226"] end end diff --git a/Library/Homebrew/upgrade.rb b/Library/Homebrew/upgrade.rb index 54e3223c18..48a1a363c9 100644 --- a/Library/Homebrew/upgrade.rb +++ b/Library/Homebrew/upgrade.rb @@ -94,22 +94,6 @@ module Homebrew .map { |k| Keg.new(k.resolved_path) } end - def print_dry_run_dependencies(formula, fi_deps) - return if fi_deps.empty? - - plural = "dependency".pluralize(fi_deps.count) - ohai "Would upgrade #{fi_deps.count} #{plural} for #{formula.full_specified_name}:" - formulae_upgrades = fi_deps.map(&:first).map(&:to_formula).map do |f| - name = f.full_specified_name - if f.optlinked? - "#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" - else - "#{name} #{f.pkg_version}" - end - end - puts formulae_upgrades.join(", ") - end - def print_upgrade_message(formula, fi_options) version_upgrade = if formula.optlinked? "#{Keg.new(formula.opt_prefix).version} -> #{formula.pkg_version}" @@ -178,7 +162,14 @@ module Homebrew formula = formula_installer.formula if dry_run - print_dry_run_dependencies(formula, formula_installer.compute_dependencies) + Install.print_dry_run_dependencies(formula, formula_installer.compute_dependencies) do |f| + name = f.full_specified_name + if f.optlinked? + "#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" + else + "#{name} #{f.pkg_version}" + end + end return end diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index f33815148b..c8dded55b9 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -13,8 +13,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-5.0.0/l $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/addressable-2.8.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.11/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-21/2.6.0/msgpack-1.5.6" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.6/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-21/2.6.0/msgpack-1.6.0" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.6.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-21/2.6.0/bootsnap-1.13.0" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.13.0/lib" $:.unshift "#{path}/" @@ -82,7 +82,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-its-1.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.9.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.5.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.6.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.21.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.11.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-2.3.0/lib" diff --git a/completions/bash/brew b/completions/bash/brew index 10cd747cb7..7c789ac9b0 100644 --- a/completions/bash/brew +++ b/completions/bash/brew @@ -1112,6 +1112,7 @@ _brew_instal() { --debug-symbols --dictionarydir --display-times + --dry-run --fetch-HEAD --fontdir --force @@ -1171,6 +1172,7 @@ _brew_install() { --debug-symbols --dictionarydir --display-times + --dry-run --fetch-HEAD --fontdir --force @@ -1261,6 +1263,7 @@ _brew_lc() { --json --newer-only --quiet + --resources --tap --verbose " @@ -1375,6 +1378,7 @@ _brew_livecheck() { --json --newer-only --quiet + --resources --tap --verbose " diff --git a/completions/fish/brew.fish b/completions/fish/brew.fish index 4b54f2d4d4..15ce52a09d 100644 --- a/completions/fish/brew.fish +++ b/completions/fish/brew.fish @@ -798,6 +798,7 @@ __fish_brew_complete_arg 'instal' -l debug -d 'If brewing fails, open an interac __fish_brew_complete_arg 'instal' -l debug-symbols -d 'Generate debug symbols on build. Source will be retained in a cache directory. ' __fish_brew_complete_arg 'instal' -l dictionarydir -d 'Target location for Dictionaries (default: `~/Library/Dictionaries`)' __fish_brew_complete_arg 'instal' -l display-times -d 'Print install times for each package at the end of the run' +__fish_brew_complete_arg 'instal' -l dry-run -d 'Show what would be installed, but do not actually install anything' __fish_brew_complete_arg 'instal' -l fetch-HEAD -d 'Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository\'s HEAD will only be checked for updates when a new stable or development version has been released' __fish_brew_complete_arg 'instal' -l fontdir -d 'Target location for Fonts (default: `~/Library/Fonts`)' __fish_brew_complete_arg 'instal' -l force -d 'Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)' @@ -848,6 +849,7 @@ __fish_brew_complete_arg 'install' -l debug -d 'If brewing fails, open an intera __fish_brew_complete_arg 'install' -l debug-symbols -d 'Generate debug symbols on build. Source will be retained in a cache directory. ' __fish_brew_complete_arg 'install' -l dictionarydir -d 'Target location for Dictionaries (default: `~/Library/Dictionaries`)' __fish_brew_complete_arg 'install' -l display-times -d 'Print install times for each package at the end of the run' +__fish_brew_complete_arg 'install' -l dry-run -d 'Show what would be installed, but do not actually install anything' __fish_brew_complete_arg 'install' -l fetch-HEAD -d 'Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository\'s HEAD will only be checked for updates when a new stable or development version has been released' __fish_brew_complete_arg 'install' -l fontdir -d 'Target location for Fonts (default: `~/Library/Fonts`)' __fish_brew_complete_arg 'install' -l force -d 'Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)' @@ -911,6 +913,7 @@ __fish_brew_complete_arg 'lc' -l installed -d 'Check formulae and casks that are __fish_brew_complete_arg 'lc' -l json -d 'Output information in JSON format' __fish_brew_complete_arg 'lc' -l newer-only -d 'Show the latest version only if it\'s newer than the formula/cask' __fish_brew_complete_arg 'lc' -l quiet -d 'Suppress warnings, don\'t print a progress bar for JSON output' +__fish_brew_complete_arg 'lc' -l resources -d 'Also check resources for formulae' __fish_brew_complete_arg 'lc' -l tap -d 'Check formulae and casks within the given tap, specified as user`/`repo' __fish_brew_complete_arg 'lc' -l verbose -d 'Make some output more verbose' __fish_brew_complete_arg 'lc; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)' @@ -980,6 +983,7 @@ __fish_brew_complete_arg 'livecheck' -l installed -d 'Check formulae and casks t __fish_brew_complete_arg 'livecheck' -l json -d 'Output information in JSON format' __fish_brew_complete_arg 'livecheck' -l newer-only -d 'Show the latest version only if it\'s newer than the formula/cask' __fish_brew_complete_arg 'livecheck' -l quiet -d 'Suppress warnings, don\'t print a progress bar for JSON output' +__fish_brew_complete_arg 'livecheck' -l resources -d 'Also check resources for formulae' __fish_brew_complete_arg 'livecheck' -l tap -d 'Check formulae and casks within the given tap, specified as user`/`repo' __fish_brew_complete_arg 'livecheck' -l verbose -d 'Make some output more verbose' __fish_brew_complete_arg 'livecheck; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)' diff --git a/completions/zsh/_brew b/completions/zsh/_brew index e219390246..933a44e42a 100644 --- a/completions/zsh/_brew +++ b/completions/zsh/_brew @@ -983,6 +983,7 @@ _brew_instal() { '(--cask)--debug-symbols[Generate debug symbols on build. Source will be retained in a cache directory. ]' \ '(--formula)--dictionarydir[Target location for Dictionaries (default: `~/Library/Dictionaries`)]' \ '(--cask)--display-times[Print install times for each package at the end of the run]' \ + '--dry-run[Show what would be installed, but do not actually install anything]' \ '(--cask)--fetch-HEAD[Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository'\''s HEAD will only be checked for updates when a new stable or development version has been released]' \ '(--formula)--fontdir[Target location for Fonts (default: `~/Library/Fonts`)]' \ '--force[Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)]' \ @@ -1037,6 +1038,7 @@ _brew_install() { '(--cask)--debug-symbols[Generate debug symbols on build. Source will be retained in a cache directory. ]' \ '(--formula)--dictionarydir[Target location for Dictionaries (default: `~/Library/Dictionaries`)]' \ '(--cask)--display-times[Print install times for each package at the end of the run]' \ + '--dry-run[Show what would be installed, but do not actually install anything]' \ '(--cask)--fetch-HEAD[Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository'\''s HEAD will only be checked for updates when a new stable or development version has been released]' \ '(--formula)--fontdir[Target location for Fonts (default: `~/Library/Fonts`)]' \ '--force[Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)]' \ @@ -1107,6 +1109,7 @@ _brew_lc() { '(--debug)--json[Output information in JSON format]' \ '--newer-only[Show the latest version only if it'\''s newer than the formula/cask]' \ '--quiet[Suppress warnings, don'\''t print a progress bar for JSON output]' \ + '--resources[Also check resources for formulae]' \ '(--eval-all --installed)--tap[Check formulae and casks within the given tap, specified as user`/`repo]' \ '--verbose[Make some output more verbose]' \ - formula \ @@ -1192,6 +1195,7 @@ _brew_livecheck() { '(--debug)--json[Output information in JSON format]' \ '--newer-only[Show the latest version only if it'\''s newer than the formula/cask]' \ '--quiet[Suppress warnings, don'\''t print a progress bar for JSON output]' \ + '--resources[Also check resources for formulae]' \ '(--eval-all --installed)--tap[Check formulae and casks within the given tap, specified as user`/`repo]' \ '--verbose[Make some output more verbose]' \ - formula \ diff --git a/docs/Brew-Livecheck.md b/docs/Brew-Livecheck.md index fbbef6c7dc..89bbf46a06 100644 --- a/docs/Brew-Livecheck.md +++ b/docs/Brew-Livecheck.md @@ -6,14 +6,14 @@ The `brew livecheck` command finds the newest version of a formula or cask's sof When livecheck isn't given instructions for how to check for upstream versions, it does the following by default: -1. For formulae: Collect the `head`, `stable`, and `homepage` URLs, in that order. For casks: Collect the `url` and `homepage` URLs, in that order. +1. For formulae: Collect the `stable`, `head`, and `homepage` URLs, in that order (resources simply use their `url`). For casks: Collect the `url` and `homepage` URLs, in that order. 1. Determine if any strategies apply to the first URL. If not, try the next URL. 1. If a strategy can be applied, use it to check for new versions. 1. Return the newest version (or an error if versions could not be found at any available URLs). It's sometimes necessary to override this default behavior to create a working check. If a source doesn't provide the newest version, we need to check a different one. If livecheck doesn't correctly match version text, we need to provide an appropriate regex or `strategy` block. -This can be accomplished by adding a `livecheck` block to the formula/cask. For more information on the available methods, please refer to the [`Livecheck` class documentation](https://rubydoc.brew.sh/Livecheck.html). +This can be accomplished by adding a `livecheck` block to the formula/cask/resource. For more information on the available methods, please refer to the [`Livecheck` class documentation](https://rubydoc.brew.sh/Livecheck.html). ## Creating a check diff --git a/docs/Manpage.md b/docs/Manpage.md index cc87074b45..1f49c87d84 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -329,6 +329,8 @@ is already installed but outdated. Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask). * `-v`, `--verbose`: Print the verification and postinstall steps. +* `-n`, `--dry-run`: + Show what would be installed, but do not actually install anything. * `--formula`: Treat all named arguments as formulae. * `--ignore-dependencies`: @@ -1267,6 +1269,8 @@ casks to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST` or Show the latest version only if it's newer than the formula/cask. * `--json`: Output information in JSON format. +* `-r`, `--resources`: + Also check resources for formulae. * `-q`, `--quiet`: Suppress warnings, don't print a progress bar for JSON output. * `--formula`: diff --git a/manpages/brew.1 b/manpages/brew.1 index add3c39520..0806010f50 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -432,6 +432,10 @@ Install formulae without checking for previously installed keg\-only or non\-mig Print the verification and postinstall steps\. . .TP +\fB\-n\fR, \fB\-\-dry\-run\fR +Show what would be installed, but do not actually install anything\. +. +.TP \fB\-\-formula\fR Treat all named arguments as formulae\. . @@ -1810,6 +1814,10 @@ Show the latest version only if it\'s newer than the formula/cask\. Output information in JSON format\. . .TP +\fB\-r\fR, \fB\-\-resources\fR +Also check resources for formulae\. +. +.TP \fB\-q\fR, \fB\-\-quiet\fR Suppress warnings, don\'t print a progress bar for JSON output\. .