From 444c3858dfc79a51cd48312bf65bccb23525a87f Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Fri, 20 Nov 2020 16:42:52 +0000 Subject: [PATCH 01/39] Adjust macOS version logic - Adjust latest supported macOS logic for e.g. Big Sur 11.1. - Updated latest supported version in docs to Mojave Fixes https://github.com/Homebrew/brew/issues/9211 --- Library/Homebrew/os/mac.rb | 12 ++++-------- Library/Homebrew/os/mac/xcode.rb | 8 ++++---- docs/Installation.md | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index 6c20bad598..2be9dfc439 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -44,13 +44,6 @@ module OS Version.new "11.0" end - def latest_stable_version - # TODO: bump version when new macOS is released and also update - # references in docs/Installation.md and - # https://github.com/Homebrew/install/blob/HEAD/install.sh - Version.new "11.0" - end - def outdated_release? # TODO: bump version when new macOS is released and also update # references in docs/Installation.md and @@ -59,7 +52,10 @@ module OS end def prerelease? - version > latest_stable_version + # TODO: bump version when new macOS is released or announced + # and also update references in docs/Installation.md and + # https://github.com/Homebrew/install/blob/HEAD/install.sh + version >= "12.0" end def languages diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb index 3ad279dc0d..daf3706fb4 100644 --- a/Library/Homebrew/os/mac/xcode.rb +++ b/Library/Homebrew/os/mac/xcode.rb @@ -22,7 +22,7 @@ module OS def latest_version latest_stable = "12.2" case MacOS.version - when "11.0" then latest_stable + when /^11\./ then latest_stable when "10.15" then "12.2" when "10.14" then "11.3.1" when "10.13" then "10.1" @@ -45,7 +45,7 @@ module OS sig { returns(String) } def minimum_version case MacOS.version - when "11.0" then "12.2" + when /^11\./ then "12.2" when "10.15" then "11.0" when "10.14" then "10.2" when "10.13" then "9.0" @@ -275,7 +275,7 @@ module OS sig { returns(String) } def latest_clang_version case MacOS.version - when "11.0", "10.15" then "1200.0.32.27" + when /^11\./, "10.15" then "1200.0.32.27" when "10.14" then "1100.0.33.17" when "10.13" then "1000.10.44.2" when "10.12" then "900.0.39.2" @@ -291,7 +291,7 @@ module OS sig { returns(String) } def minimum_version case MacOS.version - when "11.0" then "12.0.0" + when /^11\./ then "12.0.0" when "10.15" then "11.0.0" when "10.14" then "10.0.0" when "10.13" then "9.0.0" diff --git a/docs/Installation.md b/docs/Installation.md index f9ebcad45b..6bc84a6563 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -11,7 +11,7 @@ it does it too. You have to confirm everything it will do before it starts. ## macOS Requirements * A 64-bit Intel CPU [1](#1) -* macOS High Sierra (10.13) (or higher) [2](#2) +* macOS Mojave (10.14) (or higher) [2](#2) * Command Line Tools (CLT) for Xcode: `xcode-select --install`, [developer.apple.com/downloads](https://developer.apple.com/downloads) or [Xcode](https://itunes.apple.com/us/app/xcode/id497799835) [3](#3) @@ -52,7 +52,7 @@ Uninstallation is documented in the [FAQ](FAQ.md). 1 For 32-bit or PPC support see [Tigerbrew](https://github.com/mistydemeo/tigerbrew). -2 10.13 or higher is recommended. 10.9–10.12 are +2 10.14 or higher is recommended. 10.9–10.13 are supported on a best-effort basis. For 10.4-10.6 see [Tigerbrew](https://github.com/mistydemeo/tigerbrew). From a044f99d5651a6bd1a980a77c15894cb601c6ab2 Mon Sep 17 00:00:00 2001 From: Michka Popoff Date: Fri, 20 Nov 2020 22:14:56 +0100 Subject: [PATCH 02/39] on_macos/on_linux block: allow to use deprecate or disable --- Library/Homebrew/rubocops/components_order.rb | 2 ++ Library/Homebrew/test/rubocops/components_order_spec.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Library/Homebrew/rubocops/components_order.rb b/Library/Homebrew/rubocops/components_order.rb index 7f6613799c..84dba9a945 100644 --- a/Library/Homebrew/rubocops/components_order.rb +++ b/Library/Homebrew/rubocops/components_order.rb @@ -150,6 +150,8 @@ module RuboCop valid_node ||= child.method_name.to_s == "patch" valid_node ||= child.method_name.to_s == "resource" + valid_node ||= child.method_name.to_s == "deprecate!" + valid_node ||= child.method_name.to_s == "disable!" @offensive_node = on_os_block @offense_source_range = on_os_block.source_range diff --git a/Library/Homebrew/test/rubocops/components_order_spec.rb b/Library/Homebrew/test/rubocops/components_order_spec.rb index 8aa6bfc867..0a925d52ca 100644 --- a/Library/Homebrew/test/rubocops/components_order_spec.rb +++ b/Library/Homebrew/test/rubocops/components_order_spec.rb @@ -324,6 +324,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do homepage "https://brew.sh" on_macos do + disable! because: :does_not_build depends_on "readline" end @@ -341,6 +342,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do homepage "https://brew.sh" on_linux do + deprecate! because: "it's deprecated" depends_on "readline" end From 41150862840af1ceb61eace883117ae72ead5941 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 21 Nov 2020 13:29:44 +0100 Subject: [PATCH 03/39] Add Sorbet plugin for `delegate`. --- Library/Homebrew/sorbet/plugins/delegate.rb | 21 +++++++++++++++++++++ Library/Homebrew/sorbet/triggers.yml | 1 + 2 files changed, 22 insertions(+) create mode 100644 Library/Homebrew/sorbet/plugins/delegate.rb diff --git a/Library/Homebrew/sorbet/plugins/delegate.rb b/Library/Homebrew/sorbet/plugins/delegate.rb new file mode 100644 index 0000000000..2f308cc45d --- /dev/null +++ b/Library/Homebrew/sorbet/plugins/delegate.rb @@ -0,0 +1,21 @@ +# typed: strict +# frozen_string_literal: true + +source = ARGV[5] + +methods = if (single = source[/delegate\s+([^:]+):\s+/, 1]) + [single] +else + multiple = source[/delegate\s+\[(.*?)\]\s+=>\s+/m, 1] + non_comments = multiple.gsub(/\#.*$/, "") + non_comments.scan(/:([^:,\s]+)/).flatten +end + +methods.each do |method| + puts <<~RUBY + # typed: strict + + sig {params(arg0: T.untyped).returns(T.untyped)} + def #{method}(*arg0); end + RUBY +end diff --git a/Library/Homebrew/sorbet/triggers.yml b/Library/Homebrew/sorbet/triggers.yml index 48a007d979..115f740ea8 100644 --- a/Library/Homebrew/sorbet/triggers.yml +++ b/Library/Homebrew/sorbet/triggers.yml @@ -4,3 +4,4 @@ ruby_extra_args: triggers: using: sorbet/plugins/unpack_strategy_magic.rb attr_predicate: sorbet/plugins/attr_predicate.rb + delegate: sorbet/plugins/delegate.rb From b6492094d01c67c5154a23f0706a39d05703e47f Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 20 Nov 2020 12:13:53 +0100 Subject: [PATCH 04/39] Allow creating casks with `brew create --cask`. --- Library/Homebrew/cask/exceptions.rb | 2 +- Library/Homebrew/dev-cmd/create.rb | 100 ++++++++++++++++++++++------ docs/Manpage.md | 14 ++-- manpages/brew.1 | 10 ++- 4 files changed, 95 insertions(+), 31 deletions(-) diff --git a/Library/Homebrew/cask/exceptions.rb b/Library/Homebrew/cask/exceptions.rb index 9778c29725..852fa8b3ed 100644 --- a/Library/Homebrew/cask/exceptions.rb +++ b/Library/Homebrew/cask/exceptions.rb @@ -111,7 +111,7 @@ module Cask sig { returns(String) } def to_s - %Q(Cask '#{token}' already exists. Run #{Formatter.identifier("brew cask edit #{token}")} to edit it.) + %Q(Cask '#{token}' already exists. Run #{Formatter.identifier("brew edit --cask #{token}")} to edit it.) end end diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb index ea4b8a38a1..3575710c4d 100644 --- a/Library/Homebrew/dev-cmd/create.rb +++ b/Library/Homebrew/dev-cmd/create.rb @@ -6,6 +6,7 @@ require "formula_creator" require "missing_formula" require "cli/parser" require "utils/pypi" +require "cask/cask_loader" module Homebrew extend T::Sig @@ -18,14 +19,16 @@ module Homebrew usage_banner <<~EOS `create` [] - Generate a formula for the downloadable file at and open it in the editor. - Homebrew will attempt to automatically derive the formula name and version, but - if it fails, you'll have to make your own template. The `wget` formula serves as - a simple example. For the complete API, see: + Generate a formula or, with `--cask`, a cask for the downloadable file at + and open it in the editor. Homebrew will attempt to automatically derive the + formula name and version, but if it fails, you'll have to make your own template. + The `wget` formula serves as a simple example. For the complete API, see: EOS switch "--autotools", description: "Create a basic template for an Autotools-style build." + switch "--cask", + description: "Create a basic template for a cask." switch "--cmake", description: "Create a basic template for a CMake-style build." switch "--crystal", @@ -51,9 +54,10 @@ module Homebrew switch "--HEAD", description: "Indicate that points to the package's repository rather than a file." flag "--set-name=", - description: "Explicitly set the of the new formula." + description: "Explicitly set the of the new formula or cask.", + required_for: "--cask" flag "--set-version=", - description: "Explicitly set the of the new formula." + description: "Explicitly set the of the new formula or cask." flag "--set-license=", description: "Explicitly set the of the new formula." flag "--tap=", @@ -61,7 +65,12 @@ module Homebrew switch "-f", "--force", description: "Ignore errors for disallowed formula names and names that shadow aliases." - conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", "--perl", "--python", "--rust" + conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", + "--perl", "--python", "--ruby", "--rust", "--cask" + conflicts "--cask", "--HEAD" + conflicts "--cask", "--set-license" + conflicts "--cask", "--tap" + named 1 end end @@ -70,24 +79,73 @@ module Homebrew def create args = create_args.parse - # Ensure that the cache exists so we can fetch the tarball - HOMEBREW_CACHE.mkpath + path = if args.cask? + create_cask(args: args) + else + create_formula(args: args) + end - url = args.named.first # Pull the first (and only) url from ARGV + exec_editor path + end - version = args.set_version - name = args.set_name - license = args.set_license - tap = args.tap + def create_cask(args:) + url = args.named.first + if (token = args.set_name).nil? + raise UsageError, "The `--set-name` flag is required for creating casks." + end + + cask_path = Cask::CaskLoader.path(token) + raise Cask::CaskAlreadyCreatedError, token if cask_path.exist? + + version = if args.set_version + Version.create(args.set_version) + else + Version.detect(url.gsub(token, "")) + end + + interpolated_url, sha256 = if version.null? + [url, ""] + else + sha256 = if args.no_fetch? + "" + else + strategy = DownloadStrategyDetector.detect(url) + downloader = strategy.new(url, token, version.to_s, cache: Cask::Cache.path) + downloader.fetch + downloader.cached_location.sha256 + end + + [url.gsub(version.to_s, "\#{version}"), sha256] + end + + cask_path.atomic_write <<~RUBY + cask "#{token}" do + version "#{version}" + sha256 "#{sha256}" + + url "#{interpolated_url}" + name "" + desc "" + homepage "" + + app "" + end + RUBY + + puts "Please run `brew audit --cask --new #{token}` before submitting, thanks." + cask_path + end + + def create_formula(args:) fc = FormulaCreator.new(args) - fc.name = name - fc.version = version - fc.license = license - fc.tap = Tap.fetch(tap || "homebrew/core") + fc.name = args.name + fc.version = args.version + fc.license = args.license + fc.tap = Tap.fetch(args.tap || "homebrew/core") raise TapUnavailableError, tap unless fc.tap.installed? - fc.url = url + fc.url = args.named.first # Pull the first (and only) url from ARGV fc.mode = if args.cmake? :cmake @@ -143,8 +201,8 @@ module Homebrew PyPI.update_python_resources! Formula[fc.name], ignore_non_pypi_packages: true if args.python? - puts "Please run `brew audit --new-formula #{fc.name}` before submitting, thanks." - exec_editor fc.path + puts "Please run `brew audit --new #{fc.name}` before submitting, thanks." + fc.path end def __gets diff --git a/docs/Manpage.md b/docs/Manpage.md index 9e25a8c0c8..586a1639b7 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -946,14 +946,16 @@ Display the path to the file being used when invoking `brew` *`cmd`*. ### `create` [*`options`*] *`URL`* -Generate a formula for the downloadable file at *`URL`* and open it in the editor. -Homebrew will attempt to automatically derive the formula name and version, but -if it fails, you'll have to make your own template. The `wget` formula serves as -a simple example. For the complete API, see: +Generate a formula or, with `--cask`, a cask for the downloadable file at *`URL`* +and open it in the editor. Homebrew will attempt to automatically derive the +formula name and version, but if it fails, you'll have to make your own template. +The `wget` formula serves as a simple example. For the complete API, see: * `--autotools`: Create a basic template for an Autotools-style build. +* `--cask`: + Create a basic template for a cask. * `--cmake`: Create a basic template for a CMake-style build. * `--crystal`: @@ -977,9 +979,9 @@ a simple example. For the complete API, see: * `--HEAD`: Indicate that *`URL`* points to the package's repository rather than a file. * `--set-name`: - Explicitly set the *`name`* of the new formula. + Explicitly set the *`name`* of the new formula or cask. * `--set-version`: - Explicitly set the *`version`* of the new formula. + Explicitly set the *`version`* of the new formula or cask. * `--set-license`: Explicitly set the *`license`* of the new formula. * `--tap`: diff --git a/manpages/brew.1 b/manpages/brew.1 index ffa16f11d4..0b237b463f 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1316,13 +1316,17 @@ Treat all named arguments as casks\. Display the path to the file being used when invoking \fBbrew\fR \fIcmd\fR\. . .SS "\fBcreate\fR [\fIoptions\fR] \fIURL\fR" -Generate a formula for the downloadable file at \fIURL\fR and open it in the editor\. Homebrew will attempt to automatically derive the formula name and version, but if it fails, you\'ll have to make your own template\. The \fBwget\fR formula serves as a simple example\. For the complete API, see: \fIhttps://rubydoc\.brew\.sh/Formula\fR +Generate a formula or, with \fB\-\-cask\fR, a cask for the downloadable file at \fIURL\fR and open it in the editor\. Homebrew will attempt to automatically derive the formula name and version, but if it fails, you\'ll have to make your own template\. The \fBwget\fR formula serves as a simple example\. For the complete API, see: \fIhttps://rubydoc\.brew\.sh/Formula\fR . .TP \fB\-\-autotools\fR Create a basic template for an Autotools\-style build\. . .TP +\fB\-\-cask\fR +Create a basic template for a cask\. +. +.TP \fB\-\-cmake\fR Create a basic template for a CMake\-style build\. . @@ -1368,11 +1372,11 @@ Indicate that \fIURL\fR points to the package\'s repository rather than a file\. . .TP \fB\-\-set\-name\fR -Explicitly set the \fIname\fR of the new formula\. +Explicitly set the \fIname\fR of the new formula or cask\. . .TP \fB\-\-set\-version\fR -Explicitly set the \fIversion\fR of the new formula\. +Explicitly set the \fIversion\fR of the new formula or cask\. . .TP \fB\-\-set\-license\fR From 560f8e2b03d8b7558b90fe05d81447e01fcea118 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 21 Nov 2020 19:08:06 +0100 Subject: [PATCH 05/39] Fix checksum replacement in `bump-cask-pr`. --- Library/Homebrew/dev-cmd/bump-cask-pr.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bump-cask-pr.rb b/Library/Homebrew/dev-cmd/bump-cask-pr.rb index 032a8df0aa..d80201521c 100644 --- a/Library/Homebrew/dev-cmd/bump-cask-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-cask-pr.rb @@ -74,7 +74,7 @@ module Homebrew new_hash = args.sha256 old_version = cask.version - old_hash = cask.sha256 + old_hash = cask.sha256.to_s tap_full_name = cask.tap&.full_name origin_branch = Utils::Git.origin_branch(cask.tap.path) if cask.tap @@ -159,7 +159,7 @@ module Homebrew lang_cask = Cask::CaskLoader.load(tmp_contents) lang_cask.config = lang_config lang_url = lang_cask.url.to_s - lang_old_hash = lang_cask.sha256 + lang_old_hash = lang_cask.sha256.to_s resource_path = fetch_resource(cask, new_version, lang_url) Utils::Tar.validate_file(resource_path) From 9f9eaa3e6e0837b9bfc8661bbf818aa73ed8493f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Galv=C3=A3o?= Date: Sat, 21 Nov 2020 19:01:18 +0000 Subject: [PATCH 06/39] Remove amd-power-gadget from prerelease exceptions --- Library/Homebrew/utils/shared_audits.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/Library/Homebrew/utils/shared_audits.rb b/Library/Homebrew/utils/shared_audits.rb index b8fdb8c0f6..6587672c8e 100644 --- a/Library/Homebrew/utils/shared_audits.rb +++ b/Library/Homebrew/utils/shared_audits.rb @@ -32,7 +32,6 @@ module SharedAudits end GITHUB_PRERELEASE_ALLOWLIST = { - "amd-power-gadget" => :all, "elm-format" => "0.8.3", "extraterm" => :all, "freetube" => :all, From c784d9b9556e3cd3f3ebdc76957e27c5115ece0c Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 21 Nov 2020 20:11:43 +0000 Subject: [PATCH 07/39] dev-cmd/audit: Fix "undefined method audit_exceptions" - When running `brew audit` on formulae that aren't in a Homebrew tap location (ie, in a directory outside of `/usr/local/Homebrew/Library/Taps`), `brew audit` falls over because it can't determine which tap a formula is in. --- Library/Homebrew/dev-cmd/audit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index c7082b7f42..8072739efe 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -180,7 +180,7 @@ module Homebrew except: args.except, spdx_license_data: spdx_license_data, spdx_exception_data: spdx_exception_data, - tap_audit_exceptions: f.tap.audit_exceptions, + tap_audit_exceptions: f.tap&.audit_exceptions, style_offenses: style_offenses ? style_offenses.for_path(f.path) : nil, display_cop_names: args.display_cop_names?, build_stable: args.build_stable?, From 75e55def94d9f0d6ec5bb5422ad19091de88763d Mon Sep 17 00:00:00 2001 From: Michka Popoff Date: Sat, 21 Nov 2020 22:48:20 +0100 Subject: [PATCH 08/39] brew.sh: add missing quotes --- Library/Homebrew/brew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 4e4a55c8a7..3d7c06493b 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -345,7 +345,7 @@ else : "${HOMEBREW_OS_VERSION:=$(uname -r)}" HOMEBREW_OS_USER_AGENT_VERSION="$HOMEBREW_OS_VERSION" - if [[ -n $HOMEBREW_FORCE_HOMEBREW_ON_LINUX && -n $HOMEBREW_DEVELOPER && -n $HOMEBREW_ON_DEBIAN7 ]] + if [[ -n "$HOMEBREW_FORCE_HOMEBREW_ON_LINUX" && -n "$HOMEBREW_DEVELOPER" && -n "$HOMEBREW_ON_DEBIAN7" ]] then # Special version for our debian 7 docker container used to build patchelf and binutils HOMEBREW_MINIMUM_CURL_VERSION="7.25.0" From 4e1e280ace8759de737771f1f95240a1ea3afc13 Mon Sep 17 00:00:00 2001 From: Michka Popoff Date: Sun, 22 Nov 2020 00:06:25 +0100 Subject: [PATCH 09/39] brew.sh: remove HOMEBREW_DEVELOPER condition This env variable is filtered out on test-bot. --- Library/Homebrew/brew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 3d7c06493b..7e3a8e264a 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -345,7 +345,7 @@ else : "${HOMEBREW_OS_VERSION:=$(uname -r)}" HOMEBREW_OS_USER_AGENT_VERSION="$HOMEBREW_OS_VERSION" - if [[ -n "$HOMEBREW_FORCE_HOMEBREW_ON_LINUX" && -n "$HOMEBREW_DEVELOPER" && -n "$HOMEBREW_ON_DEBIAN7" ]] + if [[ -n "$HOMEBREW_FORCE_HOMEBREW_ON_LINUX" && -n "$HOMEBREW_ON_DEBIAN7" ]] then # Special version for our debian 7 docker container used to build patchelf and binutils HOMEBREW_MINIMUM_CURL_VERSION="7.25.0" From f16163c144bce958b83c73c14bd8391843e08b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Bu=CC=88nemann?= Date: Sun, 22 Nov 2020 00:43:03 +0100 Subject: [PATCH 10/39] Better check for Rosetta 2 This uses the syctl.proc_translated sysctl, which is the Apple documented way to check for Rosetta 2 environment. --- Library/Homebrew/extend/os/mac/hardware/cpu.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/extend/os/mac/hardware/cpu.rb b/Library/Homebrew/extend/os/mac/hardware/cpu.rb index 7b10da535a..ad84a72420 100644 --- a/Library/Homebrew/extend/os/mac/hardware/cpu.rb +++ b/Library/Homebrew/extend/os/mac/hardware/cpu.rb @@ -69,7 +69,7 @@ module Hardware # conflict between what `uname` reports and the underlying `sysctl` flags, # since the `sysctl` flags don't change behaviour under Rosetta 2. def in_rosetta2? - intel? && physical_cpu_arm64? + sysctl_bool("sysctl.proc_translated") end def features From 84de3c1eb6c5f69ac08a8a4ef81060e037cc0e5c Mon Sep 17 00:00:00 2001 From: Dustin Rodrigues Date: Sun, 22 Nov 2020 10:45:06 -0500 Subject: [PATCH 11/39] python: allow multi-digit minor versions --- Library/Homebrew/language/python.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/language/python.rb b/Library/Homebrew/language/python.rb index 165ee1da28..5fa55214cc 100644 --- a/Library/Homebrew/language/python.rb +++ b/Library/Homebrew/language/python.rb @@ -7,7 +7,7 @@ module Language # @api public module Python def self.major_minor_version(python) - version = /\d\.\d/.match `#{python} --version 2>&1` + version = /\d\.\d+/.match `#{python} --version 2>&1` return unless version Version.create(version.to_s) From b92a160f745641165f2a0f11a73195e6eec740a8 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 22 Nov 2020 23:20:31 +0100 Subject: [PATCH 12/39] Skip from Saturday/Sunday to end of Monday. --- .github/workflows/triage.yml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 841ecfabee..06a132a8c3 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -122,18 +122,23 @@ jobs: const reviewStartDate = new Date(pullRequest.created_at) const reviewEndDate = new Date(reviewStartDate) - switch (reviewStartDate.getDay()) { - // Skip from Friday to Monday and from Saturday to Tuesday. + switch (reviewStartDate.getUTCDay()) { case 5: - case 6: - reviewEndDate.setDate(reviewStartDate.getDate() + 3) + // Skip from Friday to Monday. + reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 3) + break + case 6: + // Skip from Saturday to end of Monday. + reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 2) + reviewEndDate.setUTCHours(23, 59, 59) break - // Skip from Sunday to Tuesday. case 0: - reviewEndDate.setDate(reviewStartDate.getDate() + 2) + // Skip from Sunday to end of Monday. + reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 1) + reviewEndDate.setUTCHours(23, 59, 59) break default: - reviewEndDate.setDate(reviewStartDate.getDate() + 1) + reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 1) break } From c00054f3ba95d97fbcab1f13b6182809808b5770 Mon Sep 17 00:00:00 2001 From: BrewTestBot <1589480+BrewTestBot@users.noreply.github.com> Date: Mon, 23 Nov 2020 00:44:39 +0000 Subject: [PATCH 13/39] sorbet: Update RBI files. Autogenerated by the [sorbet](https://github.com/Homebrew/brew/blob/master/.github/workflows/sorbet.yml) workflow. --- .../sorbet/rbi/hidden-definitions/hidden.rbi | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi index c49adbb35a..6d06779583 100644 --- a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi +++ b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi @@ -5841,22 +5841,6 @@ module Cask::Utils extend ::T::Private::Methods::SingletonMethodHooks end -class Caveats - def empty?(*args, &block); end - - def to_s(*args, &block); end -end - -class Checksum - def [](*args, &block); end - - def empty?(*args, &block); end - - def length(*args, &block); end - - def to_s(*args, &block); end -end - class Class def any_instance(); end @@ -11897,14 +11881,6 @@ module MachO def self.open(filename); end end -module MachOShim - def delete_rpath(*args, &block); end - - def dylib_id(*args, &block); end - - def rpaths(*args, &block); end -end - Markdown = RDiscount module Marshal @@ -15369,18 +15345,6 @@ class Pathname extend ::T::Private::Methods::SingletonMethodHooks end -class PkgVersion - def major(*args, &block); end - - def major_minor(*args, &block); end - - def major_minor_patch(*args, &block); end - - def minor(*args, &block); end - - def patch(*args, &block); end -end - class Proc include ::MethodSource::SourceLocation::ProcExtensions include ::MethodSource::MethodExtensions From 0424940496d69d1520043035e0993ad9c79c5cc5 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 20 Nov 2020 14:20:38 +0100 Subject: [PATCH 14/39] Add types for `ENV` extensions. --- Library/Homebrew/env_config.rb | 1 + Library/Homebrew/extend/ENV.rb | 47 ++++++-- Library/Homebrew/extend/ENV.rbi | 49 ++++++++ Library/Homebrew/extend/ENV/shared.rb | 109 +++++++++++++----- Library/Homebrew/extend/ENV/shared.rbi | 15 +++ Library/Homebrew/extend/ENV/std.rb | 56 ++++++--- Library/Homebrew/extend/ENV/super.rb | 53 +++++++-- .../extend/os/mac/extend/ENV/super.rb | 2 +- Library/Homebrew/utils/inreplace.rb | 2 +- 9 files changed, 268 insertions(+), 66 deletions(-) create mode 100644 Library/Homebrew/extend/ENV.rbi create mode 100644 Library/Homebrew/extend/ENV/shared.rbi diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb index 713c460222..e6675f14f0 100644 --- a/Library/Homebrew/env_config.rb +++ b/Library/Homebrew/env_config.rb @@ -351,6 +351,7 @@ module Homebrew end # Needs a custom implementation. + sig { returns(String) } def make_jobs jobs = ENV["HOMEBREW_MAKE_JOBS"].to_i return jobs.to_s if jobs.positive? diff --git a/Library/Homebrew/extend/ENV.rb b/Library/Homebrew/extend/ENV.rb index 17a6fd1227..d83beea7dc 100644 --- a/Library/Homebrew/extend/ENV.rb +++ b/Library/Homebrew/extend/ENV.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: strict # frozen_string_literal: true require "hardware" @@ -7,11 +7,22 @@ require "extend/ENV/shared" require "extend/ENV/std" require "extend/ENV/super" -def superenv?(env) - env != "std" && Superenv.bin +module Kernel + extend T::Sig + + sig { params(env: T.nilable(String)).returns(T::Boolean) } + def superenv?(env) + return false if env == "std" + + !Superenv.bin.nil? + end + private :superenv? end module EnvActivation + extend T::Sig + + sig { params(env: T.nilable(String)).void } def activate_extensions!(env: nil) if superenv?(env) extend(Superenv) @@ -20,25 +31,41 @@ module EnvActivation end end - def with_build_environment(env: nil, cc: nil, build_bottle: false, bottle_arch: nil) + sig do + params( + env: T.nilable(String), + cc: T.nilable(String), + build_bottle: T.nilable(T::Boolean), + bottle_arch: T.nilable(String), + _block: T.proc.returns(T.untyped), + ).returns(T.untyped) + end + def with_build_environment(env: nil, cc: nil, build_bottle: false, bottle_arch: nil, &_block) old_env = to_hash.dup tmp_env = to_hash.dup.extend(EnvActivation) - tmp_env.activate_extensions!(env: env) - tmp_env.setup_build_environment(cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch) + T.cast(tmp_env, EnvActivation).activate_extensions!(env: env) + T.cast(tmp_env, T.any(Superenv, Stdenv)) + .setup_build_environment(cc: cc, build_bottle: build_bottle, bottle_arch: bottle_arch) replace(tmp_env) - yield - ensure - replace(old_env) + + begin + yield + ensure + replace(old_env) + end end + sig { params(key: T.any(String, Symbol)).returns(T::Boolean) } def sensitive?(key) - /(cookie|key|token|password)/i =~ key + key.match?(/(cookie|key|token|password)/i) end + sig { returns(T::Hash[String, String]) } def sensitive_environment select { |key, _| sensitive?(key) } end + sig { void } def clear_sensitive_environment! each_key { |key| delete key if sensitive?(key) } end diff --git a/Library/Homebrew/extend/ENV.rbi b/Library/Homebrew/extend/ENV.rbi new file mode 100644 index 0000000000..edee664dba --- /dev/null +++ b/Library/Homebrew/extend/ENV.rbi @@ -0,0 +1,49 @@ +# typed: strict + +module EnvMethods + include Kernel + + sig { params(key: String).returns(T::Boolean) } + def key?(key); end + + sig { params(key: String).returns(T.nilable(String)) } + def [](key); end + + sig { params(key: String).returns(String) } + def fetch(key); end + + sig { params(key: String, value: T.nilable(T.any(String, PATH))).returns(T.nilable(String)) } + def []=(key, value); end + + sig { params(block: T.proc.params(arg0: [String, String]).returns(T::Boolean)).returns(T::Hash[String, String]) } + def select(&block); end + + sig { params(block: T.proc.params(arg0: String).void).void } + def each_key(&block); end + + sig { params(key: String).returns(T.nilable(String)) } + def delete(key); end + + sig do + params(other: T.any(T::Hash[String, String], Sorbet::Private::Static::ENVClass)) + .returns(Sorbet::Private::Static::ENVClass) + end + def replace(other); end + + sig { returns(T::Hash[String, String]) } + def to_hash; end +end + +module EnvActivation + include EnvMethods +end + +class Sorbet + module Private + module Static + class ENVClass + include EnvActivation + end + end + end +end diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb index ae49480479..eac0a305d4 100644 --- a/Library/Homebrew/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/ENV/shared.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "compilers" @@ -11,13 +11,16 @@ require "development_tools" # @see Stdenv # @see https://www.rubydoc.info/stdlib/Env Ruby's ENV API module SharedEnvExtension + extend T::Sig + include CompilerConstants - # @private CC_FLAG_VARS = %w[CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS].freeze - # @private + private_constant :CC_FLAG_VARS + FC_FLAG_VARS = %w[FCFLAGS FFLAGS].freeze - # @private + private_constant :FC_FLAG_VARS + SANITIZED_VARS = %w[ CDPATH CLICOLOR_FORCE CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH @@ -28,8 +31,16 @@ module SharedEnvExtension GOBIN GOPATH GOROOT PERL_MB_OPT PERL_MM_OPT LIBRARY_PATH LD_LIBRARY_PATH LD_PRELOAD LD_RUN_PATH ].freeze + private_constant :SANITIZED_VARS - # @private + sig do + params( + formula: T.nilable(Formula), + cc: T.nilable(String), + build_bottle: T.nilable(T::Boolean), + bottle_arch: T.nilable(T::Boolean), + ).void + end def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil) @formula = formula @cc = cc @@ -37,57 +48,62 @@ module SharedEnvExtension @bottle_arch = bottle_arch reset end + private :setup_build_environment - # @private + sig { void } def reset SANITIZED_VARS.each { |k| delete(k) } end + private :reset + sig { returns(T::Hash[String, String]) } def remove_cc_etc keys = %w[CC CXX OBJC OBJCXX LD CPP CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS LDFLAGS CPPFLAGS] - removed = Hash[*keys.flat_map { |key| [key, self[key]] }] - keys.each do |key| - delete(key) - end - removed + keys.map { |key| [key, delete(key)] }.to_h end + sig { params(newflags: String).void } def append_to_cflags(newflags) append(CC_FLAG_VARS, newflags) end + sig { params(val: T.any(Regexp, String)).void } def remove_from_cflags(val) remove CC_FLAG_VARS, val end + sig { params(value: String).void } def append_to_cccfg(value) append("HOMEBREW_CCCFG", value, "") end + sig { params(keys: T.any(String, T::Array[String]), value: T.untyped, separator: String).void } def append(keys, value, separator = " ") value = value.to_s Array(keys).each do |key| - old = self[key] - if old.nil? || old.empty? - self[key] = value + old_value = self[key] + self[key] = if old_value.nil? || old_value.empty? + value else - self[key] += separator + value + old_value + separator + value end end end + sig { params(keys: T.any(String, T::Array[String]), value: T.untyped, separator: String).void } def prepend(keys, value, separator = " ") value = value.to_s Array(keys).each do |key| - old = self[key] - self[key] = if old.nil? || old.empty? + old_value = self[key] + self[key] = if old_value.nil? || old_value.empty? value else - value + separator + old + value + separator + old_value end end end + sig { params(key: String, path: String).void } def append_path(key, path) self[key] = PATH.new(self[key]).append(path) end @@ -99,61 +115,78 @@ module SharedEnvExtension # Prepending a system path such as /usr/bin is a no-op so that requirements # don't accidentally override superenv shims or formulae's `bin` directories. #
ENV.prepend_path "PATH", which("emacs").dirname
+ sig { params(key: String, path: String).void } 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 + sig { params(key: String, path: T.any(String, Pathname)).void } def prepend_create_path(key, path) - path = Pathname.new(path) unless path.is_a? Pathname + path = Pathname(path) path.mkpath prepend_path key, path end + sig { params(keys: T.any(String, T::Array[String]), value: T.untyped).void } def remove(keys, value) return if value.nil? Array(keys).each do |key| - next unless self[key] + old_value = self[key] + next if old_value.nil? - self[key] = self[key].sub(value, "") - delete(key) if self[key].empty? + new_value = old_value.sub(value, "") + if new_value.empty? + delete(key) + else + self[key] = new_value + end end end + sig { returns(T.nilable(String)) } def cc self["CC"] end + sig { returns(T.nilable(String)) } def cxx self["CXX"] end + sig { returns(T.nilable(String)) } def cflags self["CFLAGS"] end + sig { returns(T.nilable(String)) } def cxxflags self["CXXFLAGS"] end + sig { returns(T.nilable(String)) } def cppflags self["CPPFLAGS"] end + sig { returns(T.nilable(String)) } def ldflags self["LDFLAGS"] end + sig { returns(T.nilable(String)) } def fc self["FC"] end + sig { returns(T.nilable(String)) } def fflags self["FFLAGS"] end + sig { returns(T.nilable(String)) } def fcflags self["FCFLAGS"] end @@ -164,8 +197,7 @@ module SharedEnvExtension # # modify CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS in one go: # ENV.append_to_cflags "-I ./missing/includes" # end - # - # @return [Symbol] + sig { returns(T.any(Symbol, String)) } def compiler @compiler ||= if (cc = @cc) warn_about_non_apple_gcc(cc) if cc.match?(GNU_GCC_REGEXP) @@ -189,27 +221,31 @@ module SharedEnvExtension end end - # @private + sig { returns(T.any(String, Pathname)) } def determine_cc COMPILER_SYMBOL_MAP.invert.fetch(compiler, compiler) end + private :determine_cc COMPILERS.each do |compiler| define_method(compiler) do @compiler = compiler - self.cc = determine_cc - self.cxx = determine_cxx + + send(:cc=, send(:determine_cc)) + send(:cxx=, send(:determine_cxx)) end end # Snow Leopard defines an NCURSES value the opposite of most distros. # @see https://bugs.python.org/issue6848 # Currently only used by aalib in core. + sig { void } def ncurses_define append "CPPFLAGS", "-DNCURSES_OPAQUE=0" end # @private + sig { void } def userpaths! path = PATH.new(self["PATH"]).select do |p| # put Superenv.bin and opt path at the first @@ -228,6 +264,7 @@ module SharedEnvExtension self["PATH"] = path end + sig { void } def fortran # Ignore repeated calls to this function as it will misleadingly warn about # building with an alternative Fortran compiler without optimization flags, @@ -260,6 +297,7 @@ module SharedEnvExtension end # @private + sig { returns(Symbol) } def effective_arch if @build_bottle && @bottle_arch @bottle_arch.to_sym @@ -269,6 +307,7 @@ module SharedEnvExtension end # @private + sig { params(name: String).returns(Formula) } def gcc_version_formula(name) version = name[GNU_GCC_REGEXP, 1] gcc_version_name = "gcc@#{version}" @@ -282,6 +321,7 @@ module SharedEnvExtension end # @private + sig { params(name: String).void } def warn_about_non_apple_gcc(name) begin gcc_formula = gcc_version_formula(name) @@ -299,30 +339,40 @@ module SharedEnvExtension EOS end + sig { void } def permit_arch_flags; end # A no-op until we enable this by default again (which we may never do). + sig { void } def permit_weak_imports; end # @private + sig { params(cc: T.any(Symbol, String)).returns(T::Boolean) } def compiler_any_clang?(cc = compiler) %w[clang llvm_clang].include?(cc.to_s) end private + sig { params(_flags: T::Array[String], _map: T::Hash[Symbol, String]).void } + def set_cpu_flags(_flags, _map = {}); end + + sig { params(val: T.any(String, Pathname)).returns(String) } def cc=(val) self["CC"] = self["OBJC"] = val.to_s end + sig { params(val: T.any(String, Pathname)).returns(String) } def cxx=(val) self["CXX"] = self["OBJCXX"] = val.to_s end + sig { returns(T.nilable(String)) } def homebrew_cc self["HOMEBREW_CC"] end + sig { params(value: String, source: String).returns(Symbol) } def fetch_compiler(value, source) COMPILER_SYMBOL_MAP.fetch(value) do |other| case other @@ -334,10 +384,9 @@ module SharedEnvExtension end end + sig { void } def check_for_compiler_universal_support - return unless homebrew_cc.match?(GNU_GCC_REGEXP) - - raise "Non-Apple GCC can't build universal binaries" + raise "Non-Apple GCC can't build universal binaries" if homebrew_cc&.match?(GNU_GCC_REGEXP) end end diff --git a/Library/Homebrew/extend/ENV/shared.rbi b/Library/Homebrew/extend/ENV/shared.rbi new file mode 100644 index 0000000000..b1eac4cd3e --- /dev/null +++ b/Library/Homebrew/extend/ENV/shared.rbi @@ -0,0 +1,15 @@ +# typed: strict + +module SharedEnvExtension + include EnvMethods +end + +class Sorbet + module Private + module Static + class ENVClass + include SharedEnvExtension + end + end + end +end diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index bea1efc156..8a8a648d81 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: strict # frozen_string_literal: true require "hardware" @@ -14,8 +14,16 @@ module Stdenv SAFE_CFLAGS_FLAGS = "-w -pipe" # @private - def setup_build_environment(**options) - super(**options) + sig do + params( + formula: T.nilable(Formula), + cc: T.nilable(String), + build_bottle: T.nilable(T::Boolean), + bottle_arch: T.nilable(T::Boolean), + ).void + end + def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil) + super self["HOMEBREW_ENV"] = "std" @@ -49,13 +57,14 @@ module Stdenv send(compiler) - return unless cc.match?(GNU_GCC_REGEXP) + return unless cc&.match?(GNU_GCC_REGEXP) gcc_formula = gcc_version_formula(cc) append_path "PATH", gcc_formula.opt_bin.to_s end alias generic_setup_build_environment setup_build_environment + sig { returns(T::Array[Pathname]) } def homebrew_extra_pkg_config_paths [] end @@ -73,10 +82,11 @@ module Stdenv # Removes the MAKEFLAGS environment variable, causing make to use a single job. # This is useful for makefiles with race conditions. # When passed a block, MAKEFLAGS is removed only for the duration of the block and is restored after its completion. - def deparallelize + sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) } + def deparallelize(&block) old = self["MAKEFLAGS"] remove "MAKEFLAGS", /-j\d+/ - if block_given? + if block begin yield ensure @@ -89,30 +99,33 @@ module Stdenv %w[O3 O2 O1 O0 Os].each do |opt| define_method opt do - remove_from_cflags(/-O./) - append_to_cflags "-#{opt}" + send(:remove_from_cflags, /-O./) + send(:append_to_cflags, "-#{opt}") end end - # @private + sig { returns(T.any(String, Pathname)) } def determine_cc s = super - DevelopmentTools.locate(s) || Pathname.new(s) + DevelopmentTools.locate(s) || Pathname(s) end + private :determine_cc - # @private + sig { returns(Pathname) } def determine_cxx - dir, base = determine_cc.split + dir, base = Pathname(determine_cc).split dir/base.to_s.sub("gcc", "g++").sub("clang", "clang++") end + private :determine_cxx GNU_GCC_VERSIONS.each do |n| define_method(:"gcc-#{n}") do super() - set_cpu_cflags + send(:set_cpu_cflags) end end + sig { void } def clang super() replace_in_cflags(/-Xarch_#{Hardware::CPU.arch_32_bit} (-march=\S*)/, '\1') @@ -124,16 +137,19 @@ module Stdenv set_cpu_cflags(map) end + sig { void } def m64 append_to_cflags "-m64" append "LDFLAGS", "-arch #{Hardware::CPU.arch_64_bit}" end + sig { void } def m32 append_to_cflags "-m32" append "LDFLAGS", "-arch #{Hardware::CPU.arch_32_bit}" end + sig { void } def universal_binary check_for_compiler_universal_support @@ -141,33 +157,38 @@ module Stdenv append "LDFLAGS", Hardware::CPU.universal_archs.as_arch_flags return if compiler_any_clang? - return unless Hardware.is_32_bit? + return unless Hardware::CPU.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 + sig { void } def cxx11 append "CXX", "-std=c++11" libcxx end + sig { void } def libcxx append "CXX", "-stdlib=libc++" if compiler == :clang end + sig { void } def libstdcxx append "CXX", "-stdlib=libstdc++" if compiler == :clang end # @private + sig { params(before: Regexp, after: String).void } def replace_in_cflags(before, after) CC_FLAG_VARS.each do |key| - self[key] = self[key].sub(before, after) if key?(key) + self[key] = fetch(key).sub(before, after) if key?(key) end end # Convenience method to set all C compiler flags in one shot. + sig { params(val: String).void } def define_cflags(val) CC_FLAG_VARS.each { |key| self[key] = val } end @@ -175,6 +196,7 @@ module Stdenv # Sets architecture-specific flags for every environment variable # given in the list `flags`. # @private + sig { params(flags: T::Array[String], map: T::Hash[Symbol, String]).void } def set_cpu_flags(flags, map = Hardware::CPU.optimization_flags) cflags =~ /(-Xarch_#{Hardware::CPU.arch_32_bit} )-march=/ xarch = Regexp.last_match(1).to_s @@ -186,19 +208,23 @@ module Stdenv append flags, map.fetch(effective_arch) end + sig { void } def x11; end # @private + sig { params(map: T::Hash[Symbol, String]).void } def set_cpu_cflags(map = Hardware::CPU.optimization_flags) # rubocop:disable Naming/AccessorMethodName set_cpu_flags(CC_FLAG_VARS, map) end + sig { returns(Integer) } def make_jobs Homebrew::EnvConfig.make_jobs.to_i end # This method does nothing in stdenv since there's no arg refurbishment # @private + sig { void } def refurbish_args; end end diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb index 4b1ba40b84..5e2c1da21f 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -1,4 +1,4 @@ -# typed: false +# typed: true # frozen_string_literal: true require "extend/ENV/shared" @@ -22,6 +22,7 @@ module Superenv # @private attr_accessor :keg_only_deps, :deps, :run_time_deps, :x11 + sig { params(base: Superenv).void } def self.extended(base) base.keg_only_deps = [] base.deps = [] @@ -29,8 +30,10 @@ module Superenv end # @private + sig { returns(T.nilable(Pathname)) } def self.bin; end + sig { void } def reset super # Configure scripts generated by autoconf 2.61 or later export as_nl, which @@ -39,8 +42,16 @@ module Superenv end # @private - def setup_build_environment(**options) - super(**options) + sig do + params( + formula: T.nilable(Formula), + cc: T.nilable(String), + build_bottle: T.nilable(T::Boolean), + bottle_arch: T.nilable(T::Boolean), + ).void + end + def setup_build_environment(formula: nil, cc: nil, build_bottle: false, bottle_arch: nil) + super send(compiler) self["HOMEBREW_ENV"] = "super" @@ -89,18 +100,22 @@ module Superenv private + sig { params(val: T.any(String, Pathname)).returns(String) } def cc=(val) self["HOMEBREW_CC"] = super end + sig { params(val: T.any(String, Pathname)).returns(String) } def cxx=(val) self["HOMEBREW_CXX"] = super end + sig { returns(String) } def determine_cxx determine_cc.to_s.gsub("gcc", "g++").gsub("clang", "clang++") end + sig { returns(T::Array[Pathname]) } def homebrew_extra_paths [] end @@ -115,7 +130,7 @@ module Superenv path.append("/usr/bin", "/bin", "/usr/sbin", "/sbin") begin - path.append(gcc_version_formula(homebrew_cc).opt_bin) if homebrew_cc.match?(GNU_GCC_REGEXP) + path.append(gcc_version_formula(T.must(homebrew_cc)).opt_bin) if homebrew_cc&.match?(GNU_GCC_REGEXP) rescue FormulaUnavailableError # Don't fail and don't add these formulae to the path if they don't exist. nil @@ -124,6 +139,7 @@ module Superenv path.existing end + sig { returns(T::Array[Pathname]) } def homebrew_extra_pkg_config_paths [] end @@ -143,6 +159,7 @@ module Superenv ).existing end + sig { returns(T::Array[Pathname]) } def homebrew_extra_aclocal_paths [] end @@ -156,6 +173,7 @@ module Superenv ).existing end + sig { returns(T::Array[Pathname]) } def homebrew_extra_isystem_paths [] end @@ -173,6 +191,7 @@ module Superenv PATH.new(keg_only_deps.map(&:opt_include)).existing end + sig { returns(T::Array[Pathname]) } def homebrew_extra_library_paths [] end @@ -187,6 +206,7 @@ module Superenv PATH.new(paths).existing end + sig { returns(String) } def determine_dependencies deps.map(&:name).join(",") end @@ -199,6 +219,7 @@ module Superenv ).existing end + sig { returns(T::Array[Pathname]) } def homebrew_extra_cmake_include_paths [] end @@ -208,6 +229,7 @@ module Superenv PATH.new(homebrew_extra_cmake_include_paths).existing end + sig { returns(T::Array[Pathname]) } def homebrew_extra_cmake_library_paths [] end @@ -217,6 +239,7 @@ module Superenv PATH.new(homebrew_extra_cmake_library_paths).existing end + sig { returns(T::Array[Pathname]) } def homebrew_extra_cmake_frameworks_paths [] end @@ -229,14 +252,17 @@ module Superenv ).existing end + sig { returns(String) } def determine_make_jobs Homebrew::EnvConfig.make_jobs end + sig { returns(String) } def determine_optflags Hardware::CPU.optimization_flags.fetch(effective_arch) end + sig { returns(String) } def determine_cccfg "" end @@ -246,9 +272,10 @@ module Superenv # Removes the MAKEFLAGS environment variable, causing make to use a single job. # This is useful for makefiles with race conditions. # When passed a block, MAKEFLAGS is removed only for the duration of the block and is restored after its completion. - def deparallelize + sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) } + def deparallelize(&block) old = delete("MAKEFLAGS") - if block_given? + if block begin yield ensure @@ -259,56 +286,64 @@ module Superenv old end + sig { returns(Integer) } def make_jobs self["MAKEFLAGS"] =~ /-\w*j(\d+)/ [Regexp.last_match(1).to_i, 1].max end + sig { void } def universal_binary check_for_compiler_universal_support self["HOMEBREW_ARCHFLAGS"] = Hardware::CPU.universal_archs.as_arch_flags end + sig { void } def permit_arch_flags append_to_cccfg "K" end + sig { void } def m32 append "HOMEBREW_ARCHFLAGS", "-m32" end + sig { void } def m64 append "HOMEBREW_ARCHFLAGS", "-m64" end + sig { void } def cxx11 append_to_cccfg "x" append_to_cccfg "g" if homebrew_cc == "clang" end + sig { void } def libcxx append_to_cccfg "g" if compiler == :clang end + sig { void } def libstdcxx append_to_cccfg "h" if compiler == :clang end # @private + sig { void } def refurbish_args append_to_cccfg "O" end %w[O3 O2 O1 O0 Os].each do |opt| define_method opt do - self["HOMEBREW_OPTIMIZATION_LEVEL"] = opt + send(:[]=, "HOMEBREW_OPTIMIZATION_LEVEL", opt) end end + sig { void } def set_x11_env_if_installed; end - - def set_cpu_flags(_arg0, _arg1 = "", _arg2 = {}); end end require "extend/os/extend/ENV/super" diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb index 4e541a2be9..d797ff7484 100644 --- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb @@ -27,7 +27,7 @@ module Superenv def homebrew_extra_paths paths = [] - paths << MacOS::XQuartz.bin.to_s if x11? + paths << MacOS::XQuartz.bin if x11? paths end diff --git a/Library/Homebrew/utils/inreplace.rb b/Library/Homebrew/utils/inreplace.rb index b414647aea..951b55148c 100644 --- a/Library/Homebrew/utils/inreplace.rb +++ b/Library/Homebrew/utils/inreplace.rb @@ -34,7 +34,7 @@ module Utils # @api public sig do params( - paths: T.any(T::Array[T.untyped], String), + paths: T.any(T::Array[T.untyped], String, Pathname), before: T.nilable(T.any(Regexp, String)), after: T.nilable(T.any(String, Symbol)), audit_result: T::Boolean, From 45ed865008409dcb1bb8d54e4b6c61684d9e5c96 Mon Sep 17 00:00:00 2001 From: Eric Knibbe Date: Sun, 22 Nov 2020 20:12:21 -0500 Subject: [PATCH 15/39] bump-cask-pr: run auto-update beforehand --- Library/Homebrew/brew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 7e3a8e264a..c9d64f1c04 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -160,7 +160,7 @@ update-preinstall() { fi if [[ "$HOMEBREW_COMMAND" = "install" || "$HOMEBREW_COMMAND" = "upgrade" || - "$HOMEBREW_COMMAND" = "bump-formula-pr" || + "$HOMEBREW_COMMAND" = "bump-formula-pr" || "$HOMEBREW_COMMAND" = "bump-cask-pr" || "$HOMEBREW_COMMAND" = "bundle" || "$HOMEBREW_COMMAND" = "tap" && $HOMEBREW_ARG_COUNT -gt 1 || "$HOMEBREW_CASK_COMMAND" = "install" || "$HOMEBREW_CASK_COMMAND" = "upgrade" ]] From 16e22bb5e8822aa8f73fad9d7e2ac42ff9a2eebc Mon Sep 17 00:00:00 2001 From: EricFromCanada Date: Sun, 22 Nov 2020 21:38:22 -0500 Subject: [PATCH 16/39] sh: skip reading user-level initialization files --- Library/Homebrew/dev-cmd/sh.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/sh.rb b/Library/Homebrew/dev-cmd/sh.rb index 3c56c13dd0..b97e2a5a48 100644 --- a/Library/Homebrew/dev-cmd/sh.rb +++ b/Library/Homebrew/dev-cmd/sh.rb @@ -54,7 +54,9 @@ module Homebrew safe_system(ENV["SHELL"], args.named.first) else subshell = if ENV["SHELL"].include?("zsh") - "PS1='brew %B%F{green}%~%f%b$ ' #{ENV["SHELL"]} -d" + "PS1='brew %B%F{green}%~%f%b$ ' #{ENV["SHELL"]} -d -f" + elsif ENV["SHELL"].include?("bash") + "PS1=\"brew \\[\\033[1;32m\\]\\w\\[\\033[0m\\]$ \" #{ENV["SHELL"]} --noprofile --norc" else "PS1=\"brew \\[\\033[1;32m\\]\\w\\[\\033[0m\\]$ \" #{ENV["SHELL"]}" end From 16736755ff8cd8cda020acd6ae065c2a7141d040 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 23 Nov 2020 05:08:05 +0100 Subject: [PATCH 17/39] Skip review for pull requests by BrewTestBot. --- .github/workflows/triage.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 06a132a8c3..fd319fc0f1 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -108,6 +108,12 @@ jobs: pull_number: pullRequestNumber, }) + const { data: user } = await github.users.getAuthenticated() + if (pullRequest.user.login == user) { + core.warning('Pull request author is a bot.') + return + } + if (pullRequest.author_association != 'MEMBER') { core.warning('Pull request author is not a member.') return From d5b184d17a9ffcfd5ad1c7c6780633a53e3f8086 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 23 Nov 2020 02:05:50 +0100 Subject: [PATCH 18/39] Add types for `SystemCommand`. --- Library/Homebrew/context.rb | 6 +- .../{unpack_strategy_magic.rb => using.rb} | 12 ++- .../sorbet/rbi/hidden-definitions/hidden.rbi | 7 ++ Library/Homebrew/sorbet/triggers.yml | 2 +- Library/Homebrew/system_command.rb | 91 +++++++++++++------ .../artifact/shared_examples/uninstall_zap.rb | 42 ++++----- .../Homebrew/test/cask/dsl/postflight_spec.rb | 3 +- .../Homebrew/test/cask/dsl/preflight_spec.rb | 3 +- .../test/cask/dsl/shared_examples/staged.rb | 34 +++---- .../cask/dsl/uninstall_postflight_spec.rb | 2 +- .../test/cask/dsl/uninstall_preflight_spec.rb | 3 +- Library/Homebrew/test/cask/pkg_spec.rb | 8 +- .../helper/cask/fake_system_command.rb | 74 --------------- .../spec/shared_context/homebrew_cask.rb | 1 - 14 files changed, 132 insertions(+), 156 deletions(-) rename Library/Homebrew/sorbet/plugins/{unpack_strategy_magic.rb => using.rb} (57%) delete mode 100644 Library/Homebrew/test/support/helper/cask/fake_system_command.rb diff --git a/Library/Homebrew/context.rb b/Library/Homebrew/context.rb index 60c354af1e..7655c8eaa7 100644 --- a/Library/Homebrew/context.rb +++ b/Library/Homebrew/context.rb @@ -34,15 +34,15 @@ module Context end def debug? - @debug + @debug == true end def quiet? - @quiet + @quiet == true end def verbose? - @verbose + @verbose == true end end diff --git a/Library/Homebrew/sorbet/plugins/unpack_strategy_magic.rb b/Library/Homebrew/sorbet/plugins/using.rb similarity index 57% rename from Library/Homebrew/sorbet/plugins/unpack_strategy_magic.rb rename to Library/Homebrew/sorbet/plugins/using.rb index d5c83fa8b5..e1bf761b29 100644 --- a/Library/Homebrew/sorbet/plugins/unpack_strategy_magic.rb +++ b/Library/Homebrew/sorbet/plugins/using.rb @@ -3,7 +3,8 @@ source = ARGV[5] -/\busing +Magic\b/.match(source) do |_| +case source[/\Ausing\s+(.*)\Z/, 1] +when "Magic" puts <<-RUBY # typed: strict @@ -18,4 +19,13 @@ source = ARGV[5] def zipinfo; end end RUBY +when "HashValidator" + puts <<-RUBY + # typed: strict + + class ::Hash + sig { params(valid_keys: T.untyped).void } + def assert_valid_keys!(*valid_keys); end + end + RUBY end diff --git a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi index 6d06779583..a9699d5831 100644 --- a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi +++ b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi @@ -28559,6 +28559,7 @@ class Socket IPV6_PATHMTU = ::T.let(nil, ::T.untyped) IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped) IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped) + IP_DONTFRAG = ::T.let(nil, ::T.untyped) IP_PORTRANGE = ::T.let(nil, ::T.untyped) IP_RECVDSTADDR = ::T.let(nil, ::T.untyped) IP_RECVIF = ::T.let(nil, ::T.untyped) @@ -28650,6 +28651,7 @@ module Socket::Constants IPV6_PATHMTU = ::T.let(nil, ::T.untyped) IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped) IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped) + IP_DONTFRAG = ::T.let(nil, ::T.untyped) IP_PORTRANGE = ::T.let(nil, ::T.untyped) IP_RECVDSTADDR = ::T.let(nil, ::T.untyped) IP_RECVIF = ::T.let(nil, ::T.untyped) @@ -29210,6 +29212,11 @@ end class SynchronizedDelegator end +class SystemCommand::Result + extend ::T::Private::Methods::MethodHooks + extend ::T::Private::Methods::SingletonMethodHooks +end + class SystemCommand extend ::T::Private::Methods::MethodHooks extend ::T::Private::Methods::SingletonMethodHooks diff --git a/Library/Homebrew/sorbet/triggers.yml b/Library/Homebrew/sorbet/triggers.yml index 115f740ea8..747e297c2e 100644 --- a/Library/Homebrew/sorbet/triggers.yml +++ b/Library/Homebrew/sorbet/triggers.yml @@ -2,6 +2,6 @@ ruby_extra_args: - --disable-gems triggers: - using: sorbet/plugins/unpack_strategy_magic.rb + using: sorbet/plugins/using.rb attr_predicate: sorbet/plugins/attr_predicate.rb delegate: sorbet/plugins/delegate.rb diff --git a/Library/Homebrew/system_command.rb b/Library/Homebrew/system_command.rb index a9ef6cf6b5..33ce5069bc 100644 --- a/Library/Homebrew/system_command.rb +++ b/Library/Homebrew/system_command.rb @@ -9,7 +9,6 @@ require "shellwords" require "extend/io" require "extend/predicable" require "extend/hash_validator" -using HashValidator # Class for running sub-processes and capturing their output and exit status. # @@ -17,14 +16,16 @@ using HashValidator class SystemCommand extend T::Sig + using HashValidator + # Helper functions for calling {SystemCommand.run}. module Mixin def system_command(*args) - SystemCommand.run(*args) + T.unsafe(SystemCommand).run(*args) end def system_command!(*args) - SystemCommand.run!(*args) + T.unsafe(SystemCommand).run!(*args) end end @@ -34,11 +35,11 @@ class SystemCommand attr_reader :pid def self.run(executable, **options) - new(executable, **options).run! + T.unsafe(self).new(executable, **options).run! end def self.run!(command, **options) - run(command, **options, must_succeed: true) + T.unsafe(self).run(command, **options, must_succeed: true) end sig { returns(SystemCommand::Result) } @@ -63,45 +64,61 @@ class SystemCommand result end + sig do + params( + executable: T.any(String, Pathname), + args: T::Array[T.any(String, Integer, Float, URI::Generic)], + sudo: T::Boolean, + env: T::Hash[String, String], + input: T.any(String, T::Array[String]), + must_succeed: T::Boolean, + print_stdout: T::Boolean, + print_stderr: T::Boolean, + verbose: T::Boolean, + secrets: T::Array[String], + chdir: T.any(String, Pathname), + ).void + end def initialize(executable, args: [], sudo: false, env: {}, input: [], must_succeed: false, - print_stdout: false, print_stderr: true, verbose: false, secrets: [], **options) + print_stdout: false, print_stderr: true, verbose: false, secrets: [], chdir: T.unsafe(nil)) require "extend/ENV" @executable = executable @args = args @sudo = sudo - @input = Array(input) - @print_stdout = print_stdout - @print_stderr = print_stderr - @verbose = verbose - @secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq - @must_succeed = must_succeed - options.assert_valid_keys!(:chdir) - @options = options - @env = env - - @env.each_key do |name| + env.each_key do |name| next if /^[\w&&\D]\w*$/.match?(name) raise ArgumentError, "Invalid variable name: '#{name}'" end + @env = env + @input = Array(input) + @must_succeed = must_succeed + @print_stdout = print_stdout + @print_stderr = print_stderr + @verbose = verbose + @secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq + @chdir = chdir end + sig { returns(T::Array[String]) } def command [*sudo_prefix, *env_args, executable.to_s, *expanded_args] end private - attr_reader :executable, :args, :input, :options, :env + attr_reader :executable, :args, :input, :chdir, :env attr_predicate :sudo?, :print_stdout?, :print_stderr?, :must_succeed? + sig { returns(T::Boolean) } def verbose? return super if @verbose.nil? @verbose end + sig { returns(T::Array[String]) } def env_args set_variables = env.compact.map do |name, value| sanitized_name = Shellwords.escape(name) @@ -114,6 +131,7 @@ class SystemCommand ["/usr/bin/env", *set_variables] end + sig { returns(T::Array[String]) } def sudo_prefix return [] unless sudo? @@ -121,11 +139,12 @@ class SystemCommand ["/usr/bin/sudo", *askpass_flags, "-E", "--"] end + sig { returns(T::Array[String]) } def expanded_args @expanded_args ||= args.map do |arg| if arg.respond_to?(:to_path) File.absolute_path(arg) - elsif arg.is_a?(Integer) || arg.is_a?(Float) || arg.is_a?(URI) + elsif arg.is_a?(Integer) || arg.is_a?(Float) || arg.is_a?(URI::Generic) arg.to_s else arg.to_str @@ -137,7 +156,7 @@ class SystemCommand executable, *args = command raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = - Open3.popen3(env, [executable, executable], *args, **options) + T.unsafe(Open3).popen3(env, [executable, executable], *args, **{ chdir: chdir }.compact) @pid = raw_wait_thr.pid write_input_to(raw_stdin) @@ -158,7 +177,7 @@ class SystemCommand loop do readable_sources, = IO.select(sources) - readable_sources = readable_sources.reject(&:eof?) + readable_sources = T.must(readable_sources).reject(&:eof?) break if readable_sources.empty? @@ -176,10 +195,20 @@ class SystemCommand # Result containing the output and exit status of a finished sub-process. class Result + extend T::Sig + include Context attr_accessor :command, :status, :exit_status + sig do + params( + command: T::Array[String], + output: T::Array[[Symbol, String]], + status: Process::Status, + secrets: T::Array[String], + ).void + end def initialize(command, output, status, secrets:) @command = command @output = output @@ -188,57 +217,65 @@ class SystemCommand @secrets = secrets end + sig { void } def assert_success! return if @status.success? raise ErrorDuringExecution.new(command, status: @status, output: @output, secrets: @secrets) end + sig { returns(String) } def stdout @stdout ||= @output.select { |type,| type == :stdout } .map { |_, line| line } .join end + sig { returns(String) } def stderr @stderr ||= @output.select { |type,| type == :stderr } .map { |_, line| line } .join end + sig { returns(String) } def merged_output @merged_output ||= @output.map { |_, line| line } .join end + sig { returns(T::Boolean) } def success? return false if @exit_status.nil? @exit_status.zero? end + sig { returns([String, String, Process::Status]) } def to_ary [stdout, stderr, status] end + sig { returns(T.nilable(T.any(Array, Hash))) } def plist @plist ||= begin output = stdout - if /\A(?.*?)<\?\s*xml/m =~ output - output = output.sub(/\A#{Regexp.escape(garbage)}/m, "") - warn_plist_garbage(garbage) + output = output.sub(/\A(.*?)(\s*<\?\s*xml)/m) do + warn_plist_garbage(T.must(Regexp.last_match(1))) + Regexp.last_match(2) end - if %r{<\s*/\s*plist\s*>(?.*?)\Z}m =~ output - output = output.sub(/#{Regexp.escape(garbage)}\Z/, "") - warn_plist_garbage(garbage) + output = output.sub(%r{(<\s*/\s*plist\s*>\s*)(.*?)\Z}m) do + warn_plist_garbage(T.must(Regexp.last_match(2))) + Regexp.last_match(1) end Plist.parse_xml(output) end end + sig { params(garbage: String).void } def warn_plist_garbage(garbage) return unless verbose? return unless garbage.match?(/\S/) diff --git a/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb b/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb index fc91356cfb..3d97672cc4 100644 --- a/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb +++ b/Library/Homebrew/test/cask/artifact/shared_examples/uninstall_zap.rb @@ -8,7 +8,7 @@ shared_examples "#uninstall_phase or #zap_phase" do let(:artifact_dsl_key) { described_class.dsl_key } let(:artifact) { cask.artifacts.find { |a| a.is_a?(described_class) } } - let(:fake_system_command) { FakeSystemCommand } + let(:fake_system_command) { class_double(SystemCommand) } context "using :launchctl" do let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-launchctl")) } @@ -31,41 +31,37 @@ shared_examples "#uninstall_phase or #zap_phase" do end it "works when job is owned by user" do - FakeSystemCommand.stubs_command( - launchctl_list_cmd, - service_info, - ) + allow(fake_system_command).to receive(:run) + .with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: false) + .and_return(instance_double(SystemCommand::Result, stdout: service_info)) + allow(fake_system_command).to receive(:run) + .with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: true) + .and_return(instance_double(SystemCommand::Result, stdout: unknown_response)) - FakeSystemCommand.stubs_command( - sudo(launchctl_list_cmd), - unknown_response, - ) - - FakeSystemCommand.expects_command(launchctl_remove_cmd) + expect(fake_system_command).to receive(:run!) + .with("/bin/launchctl", args: ["remove", "my.fancy.package.service"], sudo: false) + .and_return(instance_double(SystemCommand::Result)) subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command) end it "works when job is owned by system" do - FakeSystemCommand.stubs_command( - launchctl_list_cmd, - unknown_response, - ) + allow(fake_system_command).to receive(:run) + .with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: false) + .and_return(instance_double(SystemCommand::Result, stdout: unknown_response)) + allow(fake_system_command).to receive(:run) + .with("/bin/launchctl", args: ["list", "my.fancy.package.service"], print_stderr: false, sudo: true) + .and_return(instance_double(SystemCommand::Result, stdout: service_info)) - FakeSystemCommand.stubs_command( - sudo(launchctl_list_cmd), - service_info, - ) - - FakeSystemCommand.expects_command(sudo(launchctl_remove_cmd)) + expect(fake_system_command).to receive(:run!) + .with("/bin/launchctl", args: ["remove", "my.fancy.package.service"], sudo: true) + .and_return(instance_double(SystemCommand::Result)) subject.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command) end end context "using :pkgutil" do - let(:fake_system_command) { class_double(SystemCommand) } - let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-pkgutil")) } let(:main_pkg_id) { "my.fancy.package.main" } diff --git a/Library/Homebrew/test/cask/dsl/postflight_spec.rb b/Library/Homebrew/test/cask/dsl/postflight_spec.rb index 259921fceb..bc36ff4367 100644 --- a/Library/Homebrew/test/cask/dsl/postflight_spec.rb +++ b/Library/Homebrew/test/cask/dsl/postflight_spec.rb @@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged" describe Cask::DSL::Postflight, :cask do let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) } - let(:dsl) { described_class.new(cask, FakeSystemCommand) } + let(:fake_system_command) { class_double(SystemCommand) } + let(:dsl) { described_class.new(cask, fake_system_command) } it_behaves_like Cask::DSL::Base diff --git a/Library/Homebrew/test/cask/dsl/preflight_spec.rb b/Library/Homebrew/test/cask/dsl/preflight_spec.rb index 93f1a60174..12cbf50b17 100644 --- a/Library/Homebrew/test/cask/dsl/preflight_spec.rb +++ b/Library/Homebrew/test/cask/dsl/preflight_spec.rb @@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged" describe Cask::DSL::Preflight, :cask do let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) } - let(:dsl) { described_class.new(cask, FakeSystemCommand) } + let(:fake_system_command) { class_double(SystemCommand) } + let(:dsl) { described_class.new(cask, fake_system_command) } it_behaves_like Cask::DSL::Base diff --git a/Library/Homebrew/test/cask/dsl/shared_examples/staged.rb b/Library/Homebrew/test/cask/dsl/shared_examples/staged.rb index b6490e825d..0036751501 100644 --- a/Library/Homebrew/test/cask/dsl/shared_examples/staged.rb +++ b/Library/Homebrew/test/cask/dsl/shared_examples/staged.rb @@ -4,8 +4,8 @@ require "cask/staged" shared_examples Cask::Staged do - let(:existing_path) { Pathname.new("/path/to/file/that/exists") } - let(:non_existent_path) { Pathname.new("/path/to/file/that/does/not/exist") } + let(:existing_path) { Pathname("/path/to/file/that/exists") } + let(:non_existent_path) { Pathname("/path/to/file/that/does/not/exist") } before do allow(existing_path).to receive(:exist?).and_return(true) @@ -17,9 +17,8 @@ shared_examples Cask::Staged do end it "can run system commands with list-form arguments" do - FakeSystemCommand.expects_command( - ["echo", "homebrew-cask", "rocks!"], - ) + expect(fake_system_command).to receive(:run!) + .with("echo", args: ["homebrew-cask", "rocks!"]) staged.system_command("echo", args: ["homebrew-cask", "rocks!"]) end @@ -28,9 +27,8 @@ shared_examples Cask::Staged do fake_pathname = existing_path allow(staged).to receive(:Pathname).and_return(fake_pathname) - FakeSystemCommand.expects_command( - ["/bin/chmod", "-R", "--", "777", fake_pathname], - ) + expect(fake_system_command).to receive(:run!) + .with("/bin/chmod", args: ["-R", "--", "777", fake_pathname], sudo: false) staged.set_permissions(fake_pathname.to_s, "777") end @@ -39,9 +37,8 @@ shared_examples Cask::Staged do fake_pathname = existing_path allow(staged).to receive(:Pathname).and_return(fake_pathname) - FakeSystemCommand.expects_command( - ["/bin/chmod", "-R", "--", "777", fake_pathname, fake_pathname], - ) + expect(fake_system_command).to receive(:run!) + .with("/bin/chmod", args: ["-R", "--", "777", fake_pathname, fake_pathname], sudo: false) staged.set_permissions([fake_pathname.to_s, fake_pathname.to_s], "777") end @@ -58,9 +55,8 @@ shared_examples Cask::Staged do allow(User).to receive(:current).and_return(User.new("fake_user")) allow(staged).to receive(:Pathname).and_return(fake_pathname) - FakeSystemCommand.expects_command( - sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname), - ) + expect(fake_system_command).to receive(:run!) + .with("/usr/sbin/chown", args: ["-R", "--", "fake_user:staff", fake_pathname], sudo: true) staged.set_ownership(fake_pathname.to_s) end @@ -71,9 +67,8 @@ shared_examples Cask::Staged do allow(User).to receive(:current).and_return(User.new("fake_user")) allow(staged).to receive(:Pathname).and_return(fake_pathname) - FakeSystemCommand.expects_command( - sudo("/usr/sbin/chown", "-R", "--", "fake_user:staff", fake_pathname, fake_pathname), - ) + expect(fake_system_command).to receive(:run!) + .with("/usr/sbin/chown", args: ["-R", "--", "fake_user:staff", fake_pathname, fake_pathname], sudo: true) staged.set_ownership([fake_pathname.to_s, fake_pathname.to_s]) end @@ -83,9 +78,8 @@ shared_examples Cask::Staged do allow(staged).to receive(:Pathname).and_return(fake_pathname) - FakeSystemCommand.expects_command( - sudo("/usr/sbin/chown", "-R", "--", "other_user:other_group", fake_pathname), - ) + expect(fake_system_command).to receive(:run!) + .with("/usr/sbin/chown", args: ["-R", "--", "other_user:other_group", fake_pathname], sudo: true) staged.set_ownership(fake_pathname.to_s, user: "other_user", group: "other_group") end diff --git a/Library/Homebrew/test/cask/dsl/uninstall_postflight_spec.rb b/Library/Homebrew/test/cask/dsl/uninstall_postflight_spec.rb index 48c7653d5f..c188142015 100644 --- a/Library/Homebrew/test/cask/dsl/uninstall_postflight_spec.rb +++ b/Library/Homebrew/test/cask/dsl/uninstall_postflight_spec.rb @@ -5,7 +5,7 @@ require "test/cask/dsl/shared_examples/base" describe Cask::DSL::UninstallPostflight, :cask do let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) } - let(:dsl) { described_class.new(cask, FakeSystemCommand) } + let(:dsl) { described_class.new(cask, class_double(SystemCommand)) } it_behaves_like Cask::DSL::Base end diff --git a/Library/Homebrew/test/cask/dsl/uninstall_preflight_spec.rb b/Library/Homebrew/test/cask/dsl/uninstall_preflight_spec.rb index 635c35c030..e8d7d5c4ff 100644 --- a/Library/Homebrew/test/cask/dsl/uninstall_preflight_spec.rb +++ b/Library/Homebrew/test/cask/dsl/uninstall_preflight_spec.rb @@ -6,7 +6,8 @@ require "test/cask/dsl/shared_examples/staged" describe Cask::DSL::UninstallPreflight, :cask do let(:cask) { Cask::CaskLoader.load(cask_path("basic-cask")) } - let(:dsl) { described_class.new(cask, FakeSystemCommand) } + let(:fake_system_command) { class_double(SystemCommand) } + let(:dsl) { described_class.new(cask, fake_system_command) } it_behaves_like Cask::DSL::Base diff --git a/Library/Homebrew/test/cask/pkg_spec.rb b/Library/Homebrew/test/cask/pkg_spec.rb index e98face38a..cd45d57cf7 100644 --- a/Library/Homebrew/test/cask/pkg_spec.rb +++ b/Library/Homebrew/test/cask/pkg_spec.rb @@ -153,8 +153,12 @@ describe Cask::Pkg, :cask do "/usr/sbin/pkgutil", args: ["--pkg-info-plist", pkg_id], ).and_return( - SystemCommand::Result.new(nil, [[:stdout, pkg_info_plist]], instance_double(Process::Status, exitstatus: 0), - secrets: []), + SystemCommand::Result.new( + ["/usr/sbin/pkgutil", "--pkg-info-plist", pkg_id], + [[:stdout, pkg_info_plist]], + instance_double(Process::Status, exitstatus: 0), + secrets: [], + ), ) info = pkg.info diff --git a/Library/Homebrew/test/support/helper/cask/fake_system_command.rb b/Library/Homebrew/test/support/helper/cask/fake_system_command.rb deleted file mode 100644 index 2587e7bc52..0000000000 --- a/Library/Homebrew/test/support/helper/cask/fake_system_command.rb +++ /dev/null @@ -1,74 +0,0 @@ -# typed: true -# frozen_string_literal: true - -def sudo(*args) - ["/usr/bin/sudo", "-E", "--"] + args.flatten -end - -class FakeSystemCommand - def self.responses - @responses ||= {} - end - - def self.expectations - @expectations ||= {} - end - - def self.system_calls - @system_calls ||= Hash.new(0) - end - - def self.clear - @responses = nil - @expectations = nil - @system_calls = nil - end - - def self.stubs_command(command, response = "") - command = command.map(&:to_s) - responses[command] = response - end - - def self.expects_command(command, response = "", times = 1) - command = command.map(&:to_s) - stubs_command(command, response) - expectations[command] = times - end - - def self.verify_expectations! - expectations.each do |command, times| - unless system_calls[command] == times - raise("expected #{command.inspect} to be run #{times} times, but got #{system_calls[command]}") - end - end - end - - def self.run(command_string, options = {}) - command = SystemCommand.new(command_string, options).command - puts command - unless responses.key?(command) - raise("no response faked for #{command.inspect}, faked responses are: #{responses.inspect}") - end - - system_calls[command] += 1 - - response = responses[command] - if response.respond_to?(:call) - response.call(command_string, options) - else - SystemCommand::Result.new(command, [[:stdout, response]], OpenStruct.new(exitstatus: 0), secrets: []) - end - end - - def self.run!(command, options = {}) - run(command, options.merge(must_succeed: true)) - end -end - -RSpec.configure do |config| - config.after do - FakeSystemCommand.verify_expectations! - ensure - FakeSystemCommand.clear - end -end diff --git a/Library/Homebrew/test/support/helper/spec/shared_context/homebrew_cask.rb b/Library/Homebrew/test/support/helper/spec/shared_context/homebrew_cask.rb index 760bd80147..1682091b97 100644 --- a/Library/Homebrew/test/support/helper/spec/shared_context/homebrew_cask.rb +++ b/Library/Homebrew/test/support/helper/spec/shared_context/homebrew_cask.rb @@ -4,7 +4,6 @@ require "cask/config" require "cask/cache" -require "test/support/helper/cask/fake_system_command" require "test/support/helper/cask/install_helper" require "test/support/helper/cask/never_sudo_system_command" From cd99f83b2a34bcc5d509d33b6e290ccda52218d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Nov 2020 06:04:29 +0000 Subject: [PATCH 19/39] Bump html-proofer from 3.17.0 to 3.17.1 in /docs Bumps [html-proofer](https://github.com/gjtorikian/html-proofer) from 3.17.0 to 3.17.1. - [Release notes](https://github.com/gjtorikian/html-proofer/releases) - [Commits](https://github.com/gjtorikian/html-proofer/compare/v3.17.0...v3.17.1) Signed-off-by: dependabot[bot] --- docs/Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 584884075e..69694766ee 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -84,7 +84,7 @@ GEM html-pipeline (2.14.0) activesupport (>= 2) nokogiri (>= 1.4) - html-proofer (3.17.0) + html-proofer (3.17.1) addressable (~> 2.3) mercenary (~> 0.3) nokogumbo (~> 2.0) @@ -219,12 +219,12 @@ GEM multipart-post (2.1.1) nokogiri (1.10.10) mini_portile2 (~> 2.4.0) - nokogumbo (2.0.2) + nokogumbo (2.0.3) nokogiri (~> 1.8, >= 1.8.4) octokit (4.18.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) - parallel (1.20.0) + parallel (1.20.1) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (3.1.1) From dbd43fe71686e60b8483b8d19045ecff22e76f54 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 23 Nov 2020 07:08:13 +0100 Subject: [PATCH 20/39] Move logic for calculating date offset into separate function. --- .github/workflows/triage.yml | 64 +++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index fd319fc0f1..16cb3b72f2 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -101,6 +101,30 @@ jobs: } } + function offsetDate(start, offsetHours, skippedDays) { + let end = new Date(start) + + end.setUTCHours(end.getUTCHours() + (offsetHours % 24)) + + while (skippedDays.includes(end.getUTCDay()) || offsetHours >= 24) { + if (!skippedDays.includes(end.getUTCDay())) { + offsetHours -= 24 + } + + end.setUTCDate(end.getUTCDate() + 1) + } + + if (skippedDays.includes(start.getUTCDay())) { + end.setUTCHours(offsetHours, 0, 0) + } + + return end + } + + function formatDate(date) { + return date.toISOString().replace(/\.\d+Z$/, ' UTC').replace('T', ' at ') + } + async function reviewPullRequest(pullRequestNumber) { const { data: pullRequest } = await github.pulls.get({ owner: context.repo.owner, @@ -126,43 +150,21 @@ jobs: const hasReviewLabel = labels.includes(reviewLabel) const hasCriticalLabel = labels.includes(criticalLabel) - const reviewStartDate = new Date(pullRequest.created_at) - const reviewEndDate = new Date(reviewStartDate) - switch (reviewStartDate.getUTCDay()) { - case 5: - // Skip from Friday to Monday. - reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 3) - break - case 6: - // Skip from Saturday to end of Monday. - reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 2) - reviewEndDate.setUTCHours(23, 59, 59) - break - case 0: - // Skip from Sunday to end of Monday. - reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 1) - reviewEndDate.setUTCHours(23, 59, 59) - break - default: - reviewEndDate.setUTCDate(reviewStartDate.getUTCDate() + 1) - break - } + const offsetHours = 24 + const skippedDays = [ + 6, // Saturday + 0, // Sunday + ] const currentDate = new Date() + const reviewStartDate = new Date(pullRequest.created_at) + const reviewEndDate = offsetDate(reviewStartDate, offsetHours, skippedDays) const reviewEnded = currentDate > reviewEndDate - function formatDate(date) { - return date.toISOString().replace(/\.\d+Z$/, ' UTC').replace('T', ' at ') - } - if (reviewEnded || hasCriticalLabel) { let message if (hasCriticalLabel && !reviewEnded) { - if (hasReviewLabel) { - message = `Review period cancelled due to \`${criticalLabel}\` label.` - } else { - message = `Review period skipped due to \`${criticalLabel}\` label.` - } + message = `Review period skipped due to \`${criticalLabel}\` label.` } else { message = 'Review period ended.' } @@ -180,7 +182,7 @@ jobs: await approvePullRequest(pullRequestNumber) } else { const message = `Review period will end on ${formatDate(reviewEndDate)}.` - core.warning(message) + core.info(message) await dismissApprovals(pullRequestNumber, 'Review period has not ended yet.') await createOrUpdateComment(pullRequestNumber, 'review-period-begin', message) From 69714cb76d0d1913ae3085e53c94d476f1bd3d59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Nov 2020 07:24:54 +0000 Subject: [PATCH 21/39] Bump sorbet from 0.5.6100 to 0.5.6101 in /Library/Homebrew Bumps [sorbet](https://github.com/sorbet/sorbet) from 0.5.6100 to 0.5.6101. - [Release notes](https://github.com/sorbet/sorbet/releases) - [Commits](https://github.com/sorbet/sorbet/commits) Signed-off-by: dependabot[bot] --- Library/Homebrew/Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index 224c2cad66..cefb8195c2 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -126,11 +126,11 @@ GEM docile (~> 1.1) simplecov-html (~> 0.11) simplecov-html (0.12.3) - sorbet (0.5.6100) - sorbet-static (= 0.5.6100) + sorbet (0.5.6101) + sorbet-static (= 0.5.6101) sorbet-runtime (0.5.6100) sorbet-runtime-stub (0.2.0) - sorbet-static (0.5.6100-universal-darwin-14) + sorbet-static (0.5.6101-universal-darwin-14) spoom (1.0.6) colorize sorbet (~> 0.5.5) From 0188d14345eac15afe0d1d29c079946c4b97623b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Nov 2020 07:25:15 +0000 Subject: [PATCH 22/39] Bump parallel_tests from 3.3.0 to 3.4.0 in /Library/Homebrew Bumps [parallel_tests](https://github.com/grosser/parallel_tests) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/grosser/parallel_tests/releases) - [Changelog](https://github.com/grosser/parallel_tests/blob/master/CHANGELOG.md) - [Commits](https://github.com/grosser/parallel_tests/compare/v3.3.0...v3.4.0) Signed-off-by: dependabot[bot] --- Library/Homebrew/Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index 224c2cad66..d1eaf5247c 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -54,8 +54,8 @@ GEM nokogiri (1.10.10) mini_portile2 (~> 2.4.0) ntlm-http (0.1.1) - parallel (1.20.0) - parallel_tests (3.3.0) + parallel (1.20.1) + parallel_tests (3.4.0) parallel parlour (4.0.1) commander (~> 4.5) From 3685659ba87218c147554a457d89412958756cf7 Mon Sep 17 00:00:00 2001 From: BrewTestBot <1589480+BrewTestBot@users.noreply.github.com> Date: Mon, 23 Nov 2020 07:31:10 +0000 Subject: [PATCH 23/39] brew vendor-gems: commit updates. --- Library/Homebrew/Gemfile.lock | 2 +- Library/Homebrew/vendor/bundle/bundler/setup.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index cefb8195c2..a622e61f77 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -128,7 +128,7 @@ GEM simplecov-html (0.12.3) sorbet (0.5.6101) sorbet-static (= 0.5.6101) - sorbet-runtime (0.5.6100) + sorbet-runtime (0.5.6101) sorbet-runtime-stub (0.2.0) sorbet-static (0.5.6101-universal-darwin-14) spoom (1.0.6) diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index fbfbedd4b5..29f0fb09fb 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -51,7 +51,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.20.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.6100/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.6101/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-4.0.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib" @@ -68,8 +68,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-mocks-3.10.0/li $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-3.10.0/lib" $:.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/sorbet-static-0.5.6100-universal-darwin-19/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.6100/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.6101-universal-darwin-19/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.6101/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.1.1/lib" From 0bf8accddabfd2007ff5a2e2ce1bb89f070d0bed Mon Sep 17 00:00:00 2001 From: BrewTestBot <1589480+BrewTestBot@users.noreply.github.com> Date: Mon, 23 Nov 2020 07:58:01 +0000 Subject: [PATCH 24/39] brew vendor-gems: commit updates. --- Library/Homebrew/vendor/bundle/bundler/setup.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index fbfbedd4b5..6527455074 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -47,8 +47,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mechanize-2.7.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/method_source-1.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.20.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.3.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.20.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.4.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.2.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.6100/lib" From 2b50ecc60e758e5e8356eeeaa6b92e590244fb63 Mon Sep 17 00:00:00 2001 From: BrewTestBot <1589480+BrewTestBot@users.noreply.github.com> Date: Mon, 23 Nov 2020 07:58:50 +0000 Subject: [PATCH 25/39] Update RBI files for parallel_tests. --- .../sorbet/rbi/gems/{parallel@1.20.0.rbi => parallel@1.20.1.rbi} | 0 .../gems/{parallel_tests@3.3.0.rbi => parallel_tests@3.4.0.rbi} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Library/Homebrew/sorbet/rbi/gems/{parallel@1.20.0.rbi => parallel@1.20.1.rbi} (100%) rename Library/Homebrew/sorbet/rbi/gems/{parallel_tests@3.3.0.rbi => parallel_tests@3.4.0.rbi} (100%) diff --git a/Library/Homebrew/sorbet/rbi/gems/parallel@1.20.0.rbi b/Library/Homebrew/sorbet/rbi/gems/parallel@1.20.1.rbi similarity index 100% rename from Library/Homebrew/sorbet/rbi/gems/parallel@1.20.0.rbi rename to Library/Homebrew/sorbet/rbi/gems/parallel@1.20.1.rbi diff --git a/Library/Homebrew/sorbet/rbi/gems/parallel_tests@3.3.0.rbi b/Library/Homebrew/sorbet/rbi/gems/parallel_tests@3.4.0.rbi similarity index 100% rename from Library/Homebrew/sorbet/rbi/gems/parallel_tests@3.3.0.rbi rename to Library/Homebrew/sorbet/rbi/gems/parallel_tests@3.4.0.rbi From 120c1695467f68e3bf89169760e156cf01b3b6b0 Mon Sep 17 00:00:00 2001 From: Michka Popoff Date: Tue, 24 Nov 2020 12:31:02 +0100 Subject: [PATCH 26/39] audit: do not check for mixed dependencies - for disabled formulae - for deprecated formulae, except for the versioned ones. --- Library/Homebrew/formula_auditor.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb index 0392b11e7e..e86f600efd 100644 --- a/Library/Homebrew/formula_auditor.rb +++ b/Library/Homebrew/formula_auditor.rb @@ -1,6 +1,7 @@ # typed: false # frozen_string_literal: true +require "deprecate_disable" require "formula_text_auditor" require "resource_auditor" @@ -325,6 +326,11 @@ module Homebrew return if version_conflicts.empty? + return if formula.disabled? + + return if formula.deprecated? && + formula.deprecation_reason != DeprecateDisable::DEPRECATE_DISABLE_REASONS[:versioned_formula] + problem <<~EOS #{formula.full_name} contains conflicting version recursive dependencies: #{version_conflicts.to_a.join ", "} From 1fc3d22ab40a79fca4ddc08ba6f925c5f983af4d Mon Sep 17 00:00:00 2001 From: Michka Popoff Date: Sun, 22 Nov 2020 15:14:42 +0100 Subject: [PATCH 27/39] pr-pull: allow to pull from multiple workflows and allow to skip missing workflows Can be used like this: brew pr-pull --workflows=tests.yml,wheezy_tests.yml --ignore-missing-artifacts=wheezy_tests.yml PRNUMBER --- Library/Homebrew/dev-cmd/pr-pull.rb | 34 +++++++++++++++++++--- Library/Homebrew/test/utils/github_spec.rb | 12 ++++++-- Library/Homebrew/utils/github.rb | 7 ++++- docs/Manpage.md | 6 +++- manpages/brew.1 | 10 ++++++- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/Library/Homebrew/dev-cmd/pr-pull.rb b/Library/Homebrew/dev-cmd/pr-pull.rb index 010d3e6acc..7e059fc478 100644 --- a/Library/Homebrew/dev-cmd/pr-pull.rb +++ b/Library/Homebrew/dev-cmd/pr-pull.rb @@ -50,7 +50,8 @@ module Homebrew depends_on: "--autosquash", description: "Message to include when autosquashing revision bumps, deletions, and rebuilds." flag "--workflow=", - description: "Retrieve artifacts from the specified workflow (default: `tests.yml`)." + description: "Retrieve artifacts from the specified workflow (default: `tests.yml`). "\ + "Legacy: use --workflows instead" flag "--artifact=", description: "Download artifacts with the specified name (default: `bottles`)." flag "--bintray-org=", @@ -62,6 +63,11 @@ module Homebrew flag "--bintray-mirror=", description: "Use the specified Bintray repository to automatically mirror stable URLs "\ "defined in the formulae (default: `mirror`)." + comma_array "--workflows=", + description: "Retrieve artifacts from the specified workflow (default: `tests.yml`) "\ + "Comma-separated list to include multiple workflows." + comma_array "--ignore-missing-artifacts=", + description: "Comma-separated list of workflows which can be ignored if they have not been run." conflicts "--clean", "--autosquash" min_named 1 @@ -357,7 +363,13 @@ module Homebrew def pr_pull args = pr_pull_args.parse - workflow = args.workflow || "tests.yml" + odeprecated "`brew pr-pull --workflow`", "`brew pr-pull --workflows=`" if args.workflow.presence + + workflows = if args.workflow.blank? + args.workflows.presence || ["tests.yml"] + else + [args.workflow].compact.presence || ["tests.yml"] + end artifact = args.artifact || "bottles" bintray_org = args.bintray_org || "homebrew" mirror_repo = args.bintray_mirror || "mirror" @@ -401,8 +413,22 @@ module Homebrew next end - url = GitHub.get_artifact_url(user, repo, pr, workflow_id: workflow, artifact_name: artifact) - download_artifact(url, dir, pr) + workflows.each do |workflow| + workflow_run = GitHub.get_workflow_run( + user, repo, pr, workflow_id: workflow, artifact_name: artifact + ) + if args.ignore_missing_artifacts.present? && + args.ignore_missing_artifacts.include?(workflow) && + workflow_run.empty? + # Ignore that workflow as it was not executed and we specified + # that we could skip it. + next + end + + ohai "Downloading bottles for workflow: #{workflow}" + url = GitHub.get_artifact_url(workflow_run) + download_artifact(url, dir, pr) + end next if args.no_upload? diff --git a/Library/Homebrew/test/utils/github_spec.rb b/Library/Homebrew/test/utils/github_spec.rb index 1949123d28..8704b8f6a5 100644 --- a/Library/Homebrew/test/utils/github_spec.rb +++ b/Library/Homebrew/test/utils/github_spec.rb @@ -61,18 +61,24 @@ describe GitHub do describe "::get_artifact_url", :needs_network do it "fails to find a nonexistant workflow" do expect { - subject.get_artifact_url("Homebrew", "homebrew-core", 1) + subject.get_artifact_url( + subject.get_workflow_run("Homebrew", "homebrew-core", 1), + ) }.to raise_error(/No matching workflow run found/) end it "fails to find artifacts that don't exist" do expect { - subject.get_artifact_url("Homebrew", "homebrew-core", 51971, artifact_name: "false_bottles") + subject.get_artifact_url( + subject.get_workflow_run("Homebrew", "homebrew-core", 51971, artifact_name: "false_bottles"), + ) }.to raise_error(/No artifact .+ was found/) end it "gets an artifact link" do - url = subject.get_artifact_url("Homebrew", "homebrew-core", 51971, artifact_name: "bottles") + url = subject.get_artifact_url( + subject.get_workflow_run("Homebrew", "homebrew-core", 51971, artifact_name: "bottles"), + ) expect(url).to eq("https://api.github.com/repos/Homebrew/homebrew-core/actions/artifacts/3557392/zip") end end diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index a235b77d74..3c2ada9ba8 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -510,7 +510,7 @@ module GitHub open_api(url, data_binary_path: local_file, request_method: :POST, scopes: CREATE_ISSUE_FORK_OR_PR_SCOPES) end - def get_artifact_url(user, repo, pr, workflow_id: "tests.yml", artifact_name: "bottles") + def get_workflow_run(user, repo, pr, workflow_id: "tests.yml", artifact_name: "bottles") scopes = CREATE_ISSUE_FORK_OR_PR_SCOPES base_url = "#{API_URL}/repos/#{user}/#{repo}" pr_payload = open_api("#{base_url}/pulls/#{pr}", scopes: scopes) @@ -523,6 +523,11 @@ module GitHub run["head_sha"] == pr_sha end + [workflow_run, pr_sha, pr_branch, pr, workflow_id, scopes, artifact_name] + end + + def get_artifact_url(workflow_array) + workflow_run, pr_sha, pr_branch, pr, workflow_id, scopes, artifact_name = *workflow_array if workflow_run.empty? raise Error, <<~EOS No matching workflow run found for these criteria! diff --git a/docs/Manpage.md b/docs/Manpage.md index 586a1639b7..014d4413dd 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1158,7 +1158,7 @@ Requires write access to the repository. * `--message`: Message to include when autosquashing revision bumps, deletions, and rebuilds. * `--workflow`: - Retrieve artifacts from the specified workflow (default: `tests.yml`). + Retrieve artifacts from the specified workflow (default: `tests.yml`). Legacy: use --workflows instead * `--artifact`: Download artifacts with the specified name (default: `bottles`). * `--bintray-org`: @@ -1169,6 +1169,10 @@ Requires write access to the repository. Use the specified *`URL`* as the root of the bottle's URL instead of Homebrew's default. * `--bintray-mirror`: Use the specified Bintray repository to automatically mirror stable URLs defined in the formulae (default: `mirror`). +* `--workflows`: + Retrieve artifacts from the specified workflow (default: `tests.yml`) Comma-separated list to include multiple workflows. +* `--ignore-missing-artifacts`: + Comma-separated list of workflows which can be ignored if they have not been run. ### `pr-upload` [*`options`*] diff --git a/manpages/brew.1 b/manpages/brew.1 index 0b237b463f..8fa25bf1ae 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1618,7 +1618,7 @@ Message to include when autosquashing revision bumps, deletions, and rebuilds\. . .TP \fB\-\-workflow\fR -Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR)\. +Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR)\. Legacy: use \-\-workflows instead . .TP \fB\-\-artifact\fR @@ -1640,6 +1640,14 @@ Use the specified \fIURL\fR as the root of the bottle\'s URL instead of Homebrew \fB\-\-bintray\-mirror\fR Use the specified Bintray repository to automatically mirror stable URLs defined in the formulae (default: \fBmirror\fR)\. . +.TP +\fB\-\-workflows\fR +Retrieve artifacts from the specified workflow (default: \fBtests\.yml\fR) Comma\-separated list to include multiple workflows\. +. +.TP +\fB\-\-ignore\-missing\-artifacts\fR +Comma\-separated list of workflows which can be ignored if they have not been run\. +. .SS "\fBpr\-upload\fR [\fIoptions\fR]" Apply the bottle commit and publish bottles to Bintray or GitHub Releases\. . From dfcfa836b8e1787924ff404d592516f816eea9df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Nov 2020 15:28:43 +0000 Subject: [PATCH 28/39] Bump reitermarkus/rerun-workflow Bumps [reitermarkus/rerun-workflow](https://github.com/reitermarkus/rerun-workflow) from cf91bee6964dfde64eccbf5600c3ea206af11359 to 1.1.5. This release includes the previously tagged commit. - [Release notes](https://github.com/reitermarkus/rerun-workflow/releases) - [Commits](https://github.com/reitermarkus/rerun-workflow/compare/cf91bee6964dfde64eccbf5600c3ea206af11359...e2647e8885422412d5acbd61f9add5b1e77ad3ab) Signed-off-by: dependabot[bot] --- .github/workflows/triage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 16cb3b72f2..dc51cd15ec 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Re-run this workflow if: github.event_name == 'schedule' || github.event.action == 'closed' - uses: reitermarkus/rerun-workflow@cf91bee6964dfde64eccbf5600c3ea206af11359 + uses: reitermarkus/rerun-workflow@e2647e8885422412d5acbd61f9add5b1e77ad3ab with: token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }} continuous-label: waiting for feedback From d496f5c121f33fd91a820f60defedd0bbc01e4c2 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Tue, 24 Nov 2020 16:44:02 +0000 Subject: [PATCH 29/39] Deprecations for Homebrew 2.6.0 Do the usual deprecate/disable dance for the Homebrew 2.6.0 release. Not to be merged until the next release will definitely be 2.6.0. --- Library/Homebrew/build_options.rb | 16 +- Library/Homebrew/cli/args.rb | 27 +-- Library/Homebrew/cmd/gist-logs.rb | 11 +- Library/Homebrew/cmd/list.rb | 3 +- Library/Homebrew/cmd/outdated.rb | 11 +- Library/Homebrew/cmd/switch.rb | 2 +- Library/Homebrew/compat.rb | 6 - .../Homebrew/compat/dependencies_helpers.rb | 18 -- .../Homebrew/compat/dependencies_helpers.rbi | 9 - Library/Homebrew/compat/extend/nil.rb | 12 -- Library/Homebrew/compat/extend/nil.rbi | 7 - Library/Homebrew/compat/extend/string.rb | 12 -- Library/Homebrew/compat/extend/string.rbi | 7 - Library/Homebrew/compat/formula.rb | 21 +-- Library/Homebrew/compat/global.rb | 3 +- Library/Homebrew/compat/language/haskell.rb | 30 +--- Library/Homebrew/compat/language/java.rb | 17 -- Library/Homebrew/compat/language/python.rb | 17 -- Library/Homebrew/compat/os/mac.rb | 24 --- Library/Homebrew/compat/os/mac.rbi | 11 -- Library/Homebrew/dev-cmd/diy.rb | 3 +- Library/Homebrew/dev-cmd/mirror.rb | 1 - Library/Homebrew/dev-cmd/pull.rb | 52 ------ .../os/mac/requirements/java_requirement.rb | 6 +- Library/Homebrew/formula.rb | 24 +-- Library/Homebrew/formulary.rb | 10 +- Library/Homebrew/patch.rb | 22 +-- .../Homebrew/requirements/java_requirement.rb | 3 + .../requirements/macos_requirement.rb | 14 +- Library/Homebrew/rubocops/text.rb | 15 -- Library/Homebrew/tab.rb | 14 +- Library/Homebrew/test/cmd/switch_spec.rb | 14 -- Library/Homebrew/test/formula_spec.rb | 14 +- Library/Homebrew/test/language/java_spec.rb | 8 +- .../test/os/mac/java_requirement_spec.rb | 38 ----- .../requirements/java_requirement_spec.rb | 159 ------------------ Library/Homebrew/test/rubocops/text_spec.rb | 55 ------ Library/Homebrew/utils/github.rb | 4 +- completions/internal_commands_list.txt | 1 - docs/Manpage.md | 22 +-- manpages/brew.1 | 26 +-- 41 files changed, 83 insertions(+), 686 deletions(-) delete mode 100644 Library/Homebrew/compat/dependencies_helpers.rb delete mode 100644 Library/Homebrew/compat/dependencies_helpers.rbi delete mode 100644 Library/Homebrew/compat/extend/nil.rb delete mode 100644 Library/Homebrew/compat/extend/nil.rbi delete mode 100644 Library/Homebrew/compat/extend/string.rb delete mode 100644 Library/Homebrew/compat/extend/string.rbi delete mode 100644 Library/Homebrew/compat/language/java.rb delete mode 100644 Library/Homebrew/compat/language/python.rb delete mode 100644 Library/Homebrew/compat/os/mac.rb delete mode 100644 Library/Homebrew/compat/os/mac.rbi delete mode 100644 Library/Homebrew/dev-cmd/pull.rb delete mode 100644 Library/Homebrew/test/os/mac/java_requirement_spec.rb delete mode 100644 Library/Homebrew/test/requirements/java_requirement_spec.rb diff --git a/Library/Homebrew/build_options.rb b/Library/Homebrew/build_options.rb index af06250a32..36ae1d613e 100644 --- a/Library/Homebrew/build_options.rb +++ b/Library/Homebrew/build_options.rb @@ -13,9 +13,8 @@ class BuildOptions # TODO: rename private_include? when include? is removed. # @deprecated - def include?(name) - odeprecated "BuildOptions#include?" - private_include?("--#{name}") + def include?(_) + odisabled "BuildOptions#include?" end # True if a {Formula} is being built with a specific option. @@ -65,11 +64,6 @@ class BuildOptions private_include? "HEAD" end - # @private - def devel? - odisabled "BuildOptions#devel?" - end - # True if a {Formula} is being built with {Formula.stable} instead of {Formula.head}. # This is the default. #
args << "--some-beta" if build.head?
@@ -81,14 +75,12 @@ class BuildOptions # e.g. on newer Intel Macs this means a combined x86_64/x86 binary/library. #
args << "--universal-binary" if build.universal?
def universal? - odeprecated "BuildOptions#universal?" - private_include?("universal") && option_defined?("universal") + odisabled "BuildOptions#universal?" end # True if a {Formula} is being built in C++11 mode. def cxx11? - odeprecated "BuildOptions#cxx11?" - private_include?("c++11") && option_defined?("c++11") + odisabled "BuildOptions#cxx11?" end # True if the build has any arguments or options specified. diff --git a/Library/Homebrew/cli/args.rb b/Library/Homebrew/cli/args.rb index c9bdd72ccf..2e878ceed8 100644 --- a/Library/Homebrew/cli/args.rb +++ b/Library/Homebrew/cli/args.rb @@ -63,48 +63,39 @@ module Homebrew end def formulae - odeprecated "args.formulae", "args.named.to_formulae" - named.to_formulae + odisabled "args.formulae", "args.named.to_formulae" end def formulae_and_casks - odeprecated "args.formulae_and_casks", "args.named.to_formulae_and_casks" - named.to_formulae_and_casks + odisabled "args.formulae_and_casks", "args.named.to_formulae_and_casks" end def resolved_formulae - odeprecated "args.resolved_formulae", "args.named.to_resolved_formulae" - named.to_resolved_formulae + odisabled "args.resolved_formulae", "args.named.to_resolved_formulae" end def resolved_formulae_casks - odeprecated "args.resolved_formulae_casks", "args.named.to_resolved_formulae_to_casks" - named.to_resolved_formulae_to_casks + odisabled "args.resolved_formulae_casks", "args.named.to_resolved_formulae_to_casks" end def formulae_paths - odeprecated "args.formulae_paths", "args.named.to_formulae_paths" - named.to_formulae_paths + odisabled "args.formulae_paths", "args.named.to_formulae_paths" end def casks - odeprecated "args.casks", "args.named.homebrew_tap_cask_names" - named.homebrew_tap_cask_names + odisabled "args.casks", "args.named.homebrew_tap_cask_names" end def loaded_casks - odeprecated "args.loaded_casks", "args.named.to_cask" - named.to_casks + odisabled "args.loaded_casks", "args.named.to_cask" end def kegs - odeprecated "args.kegs", "args.named.to_kegs" - named.to_kegs + odisabled "args.kegs", "args.named.to_kegs" end def kegs_casks - odeprecated "args.kegs", "args.named.to_kegs_to_casks" - named.to_kegs_to_casks + odisabled "args.kegs", "args.named.to_kegs_to_casks" end def build_stable? diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb index d590fb3526..a42d2457f9 100644 --- a/Library/Homebrew/cmd/gist-logs.rb +++ b/Library/Homebrew/cmd/gist-logs.rb @@ -57,16 +57,7 @@ module Homebrew files["00.tap.out"] = { content: tap } end - if GitHub.api_credentials_type == :none - puts <<~EOS - You can create a new personal access token: - #{GitHub::ALL_SCOPES_URL} - #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} - - EOS - odeprecated "`brew gist-logs` with a password", "HOMEBREW_GITHUB_API_TOKEN" - login! - end + odisabled "`brew gist-logs` with a password", "HOMEBREW_GITHUB_API_TOKEN" if GitHub.api_credentials_type == :none # Description formatted to work well as page title when viewing gist descr = if f.core_formula? diff --git a/Library/Homebrew/cmd/list.rb b/Library/Homebrew/cmd/list.rb index e7e5a97536..c67ed6e223 100644 --- a/Library/Homebrew/cmd/list.rb +++ b/Library/Homebrew/cmd/list.rb @@ -103,8 +103,7 @@ module Homebrew ls_args << "-t" if args.t? if !$stdout.tty? && !args.formula? - odeprecated "`brew list` to only list formulae", "`brew list --formula`" - safe_system "ls", *ls_args, HOMEBREW_CELLAR + odisabled "`brew list` to only list formulae", "`brew list --formula`" else safe_system "ls", *ls_args, HOMEBREW_CELLAR list_casks(args: args) unless args.formula? diff --git a/Library/Homebrew/cmd/outdated.rb b/Library/Homebrew/cmd/outdated.rb index 6cb52621cb..ea40aad78f 100644 --- a/Library/Homebrew/cmd/outdated.rb +++ b/Library/Homebrew/cmd/outdated.rb @@ -50,16 +50,7 @@ module Homebrew case (j = json_version(args.json)) when :v1, :default - odeprecated "brew outdated --json#{j == :v1 ? "=v1" : ""}", "brew outdated --json=v2" - - outdated = if args.formula? || !args.cask? - outdated_formulae args: args - else - outdated_casks args: args - end - - puts JSON.generate(json_info(outdated, args: args)) - + odisabled "brew outdated --json#{j == :v1 ? "=v1" : ""}", "brew outdated --json=v2" when :v2 formulae, casks = if args.formula? [outdated_formulae(args: args), []] diff --git a/Library/Homebrew/cmd/switch.rb b/Library/Homebrew/cmd/switch.rb index a78ef0a907..3f3e4baaf3 100644 --- a/Library/Homebrew/cmd/switch.rb +++ b/Library/Homebrew/cmd/switch.rb @@ -32,7 +32,7 @@ module Homebrew odie "#{name} not found in the Cellar." unless rack.directory? - # odeprecated "`brew switch`", "`brew link` @-versioned formulae" + odeprecated "`brew switch`", "`brew link` @-versioned formulae" versions = rack.subdirs .map { |d| Keg.new(d).version } diff --git a/Library/Homebrew/compat.rb b/Library/Homebrew/compat.rb index c9ad444268..583726728f 100644 --- a/Library/Homebrew/compat.rb +++ b/Library/Homebrew/compat.rb @@ -1,12 +1,6 @@ # typed: strict # frozen_string_literal: true -require "compat/dependencies_helpers" require "compat/cli/parser" -require "compat/extend/nil" -require "compat/extend/string" require "compat/formula" require "compat/global" -require "compat/language/java" -require "compat/language/python" -require "compat/os/mac" if OS.mac? diff --git a/Library/Homebrew/compat/dependencies_helpers.rb b/Library/Homebrew/compat/dependencies_helpers.rb deleted file mode 100644 index 21122e4c35..0000000000 --- a/Library/Homebrew/compat/dependencies_helpers.rb +++ /dev/null @@ -1,18 +0,0 @@ -# typed: true -# frozen_string_literal: true - -require "cli/args" - -module DependenciesHelpers - module Compat - def argv_includes_ignores(argv = nil) - unless @printed_includes_ignores_warning - odisabled "Homebrew.argv_includes_ignores", "Homebrew.args_includes_ignores" - @printed_includes_ignores_warning = true - end - args_includes_ignores(argv ? Homebrew::CLI::Args.new : Homebrew.args) - end - end - - prepend Compat -end diff --git a/Library/Homebrew/compat/dependencies_helpers.rbi b/Library/Homebrew/compat/dependencies_helpers.rbi deleted file mode 100644 index 3ea83b62b9..0000000000 --- a/Library/Homebrew/compat/dependencies_helpers.rbi +++ /dev/null @@ -1,9 +0,0 @@ -# typed: strict - -module DependenciesHelpers - module Compat - include Kernel - - def args_includes_ignores(args); end - end -end diff --git a/Library/Homebrew/compat/extend/nil.rb b/Library/Homebrew/compat/extend/nil.rb deleted file mode 100644 index 5e521a4367..0000000000 --- a/Library/Homebrew/compat/extend/nil.rb +++ /dev/null @@ -1,12 +0,0 @@ -# typed: true -# frozen_string_literal: true - -class NilClass - module Compat - def chuzzle - odisabled ".chuzzle", "&.chomp.presence" - end - end - - prepend Compat -end diff --git a/Library/Homebrew/compat/extend/nil.rbi b/Library/Homebrew/compat/extend/nil.rbi deleted file mode 100644 index 0a0adb9756..0000000000 --- a/Library/Homebrew/compat/extend/nil.rbi +++ /dev/null @@ -1,7 +0,0 @@ -# typed: strict - -class NilClass - module Compat - include Kernel - end -end diff --git a/Library/Homebrew/compat/extend/string.rb b/Library/Homebrew/compat/extend/string.rb deleted file mode 100644 index bdbed56112..0000000000 --- a/Library/Homebrew/compat/extend/string.rb +++ /dev/null @@ -1,12 +0,0 @@ -# typed: true -# frozen_string_literal: true - -class String - module Compat - def chuzzle - odisabled ".chuzzle", "&.chomp.presence" - end - end - - prepend Compat -end diff --git a/Library/Homebrew/compat/extend/string.rbi b/Library/Homebrew/compat/extend/string.rbi deleted file mode 100644 index 4851c5b127..0000000000 --- a/Library/Homebrew/compat/extend/string.rbi +++ /dev/null @@ -1,7 +0,0 @@ -# typed: strict - -class String - module Compat - include Kernel - end -end diff --git a/Library/Homebrew/compat/formula.rb b/Library/Homebrew/compat/formula.rb index 0f08e86d9f..fd5f98f979 100644 --- a/Library/Homebrew/compat/formula.rb +++ b/Library/Homebrew/compat/formula.rb @@ -3,33 +3,20 @@ class Formula module Compat - def installed? - odisabled "Formula#installed?", - "Formula#latest_version_installed? (or Formula#any_version_installed? )" - end - - def prepare_patches - odisabled "patches", "patch do" if respond_to?(:patches) - super - end - def installed_prefix - odeprecated "Formula#installed_prefix", - "Formula#latest_installed_prefix (or Formula#any_installed_prefix)" - latest_installed_prefix + odisabled "Formula#installed_prefix", + "Formula#latest_installed_prefix (or Formula#any_installed_prefix)" end # The currently installed version for this formula. Will raise an exception # if the formula is not installed. # @private def installed_version - odeprecated "Formula#installed_version" - Keg.new(latest_installed_prefix).version + odisabled "Formula#installed_version" end def opt_or_installed_prefix_keg - odeprecated "Formula#opt_or_installed_prefix_keg", "Formula#any_installed_keg" - any_installed_keg + odisabled "Formula#opt_or_installed_prefix_keg", "Formula#any_installed_keg" end end diff --git a/Library/Homebrew/compat/global.rb b/Library/Homebrew/compat/global.rb index 3ab5383e60..e229b7cc6e 100644 --- a/Library/Homebrew/compat/global.rb +++ b/Library/Homebrew/compat/global.rb @@ -7,8 +7,7 @@ module Homebrew def args unless @printed_args_warning - odeprecated "Homebrew.args", "`args = _args.parse` and pass `args` along the call chain" - @printed_args_warning = true + odisabled "Homebrew.args", "`args = _args.parse` and pass `args` along the call chain" end @args ||= CLI::Args.new diff --git a/Library/Homebrew/compat/language/haskell.rb b/Library/Homebrew/compat/language/haskell.rb index 3619e88c02..00f6466807 100644 --- a/Library/Homebrew/compat/language/haskell.rb +++ b/Library/Homebrew/compat/language/haskell.rb @@ -4,35 +4,9 @@ module Language module Haskell module Cabal - module Compat - def cabal_sandbox(_options = {}) - odisabled "Language::Haskell::Cabal.cabal_sandbox" - end - - def cabal_sandbox_add_source(*_args) - odisabled "Language::Haskell::Cabal.cabal_sandbox_add_source" - end - - def cabal_install(*_args) - odisabled "Language::Haskell::Cabal.cabal_install", - "cabal v2-install directly with std_cabal_v2_args" - end - - def cabal_configure(_flags) - odisabled "Language::Haskell::Cabal.cabal_configure" - end - - def cabal_install_tools(*_tools) - odisabled "Language::Haskell::Cabal.cabal_install_tools" - end - - def install_cabal_package(*_args, **_options) - odisabled "Language::Haskell::Cabal.install_cabal_package", - "cabal v2-update directly followed by v2-install with std_cabal_v2_args" - end + def self.included(_) + odisabled "include Language::Haskell::Cabal" end - - prepend Compat end end end diff --git a/Library/Homebrew/compat/language/java.rb b/Library/Homebrew/compat/language/java.rb deleted file mode 100644 index 4a23f7a6c2..0000000000 --- a/Library/Homebrew/compat/language/java.rb +++ /dev/null @@ -1,17 +0,0 @@ -# typed: false -# frozen_string_literal: true - -module Language - module Java - class << self - module Compat - def java_home_cmd(_version = nil) - odisabled "Language::Java.java_home_cmd", - "Language::Java.java_home or Language::Java.overridable_java_home_env" - end - end - - prepend Compat - end - end -end diff --git a/Library/Homebrew/compat/language/python.rb b/Library/Homebrew/compat/language/python.rb deleted file mode 100644 index abb4673f6b..0000000000 --- a/Library/Homebrew/compat/language/python.rb +++ /dev/null @@ -1,17 +0,0 @@ -# typed: false -# frozen_string_literal: true - -module Language - module Python - class << self - module Compat - def rewrite_python_shebang(_python_path) - odisabled "Language::Python.rewrite_python_shebang", - "Utils::Shebang.rewrite_shebang and Shebang.python_shebang_rewrite_info(python_path)" - end - end - - prepend Compat - end - end -end diff --git a/Library/Homebrew/compat/os/mac.rb b/Library/Homebrew/compat/os/mac.rb deleted file mode 100644 index ab64aeac96..0000000000 --- a/Library/Homebrew/compat/os/mac.rb +++ /dev/null @@ -1,24 +0,0 @@ -# typed: true -# frozen_string_literal: true - -module OS - module Mac - class << self - module Compat - def preferred_arch - odisabled "MacOS.preferred_arch", "Hardware::CPU.arch (or ideally let the compiler handle it)" - end - - def tcc_db - odisabled "MacOS.tcc_db" - end - - def pre_mavericks_accessibility_dotfile - odisabled "MacOS.pre_mavericks_accessibility_dotfile" - end - end - - prepend Compat - end - end -end diff --git a/Library/Homebrew/compat/os/mac.rbi b/Library/Homebrew/compat/os/mac.rbi deleted file mode 100644 index b6156fa2e8..0000000000 --- a/Library/Homebrew/compat/os/mac.rbi +++ /dev/null @@ -1,11 +0,0 @@ -# typed: strict - -module OS - module Mac - class << self - module Compat - include Kernel - end - end - end -end diff --git a/Library/Homebrew/dev-cmd/diy.rb b/Library/Homebrew/dev-cmd/diy.rb index 55696b2352..aba0a000ff 100644 --- a/Library/Homebrew/dev-cmd/diy.rb +++ b/Library/Homebrew/dev-cmd/diy.rb @@ -25,13 +25,14 @@ module Homebrew description: "Explicitly set the of the package being installed." max_named 0 + hide_from_man_page! end end def diy args = diy_args.parse - # odeprecated "`brew diy`" + odeprecated "`brew diy`" path = Pathname.getwd diff --git a/Library/Homebrew/dev-cmd/mirror.rb b/Library/Homebrew/dev-cmd/mirror.rb index a6c2b45b1a..29c238f6a9 100644 --- a/Library/Homebrew/dev-cmd/mirror.rb +++ b/Library/Homebrew/dev-cmd/mirror.rb @@ -25,7 +25,6 @@ module Homebrew description: "Upload to Bintray, but don't publish." min_named :formula - hide_from_man_page! end end diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb deleted file mode 100644 index ce6f69c358..0000000000 --- a/Library/Homebrew/dev-cmd/pull.rb +++ /dev/null @@ -1,52 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "net/http" -require "net/https" -require "json" -require "cli/parser" -require "formula" -require "formulary" -require "version" -require "pkg_version" -require "formula_info" - -module Homebrew - extend T::Sig - - module_function - - sig { returns(CLI::Parser) } - def pull_args - Homebrew::CLI::Parser.new do - usage_banner <<~EOS - `pull` [] - - Get a patch from a GitHub commit or pull request and apply it to Homebrew. - - Each may be the number of a pull request in `homebrew/core` - or the URL of any pull request or commit on GitHub. - EOS - switch "--bump", - description: "For one-formula PRs, automatically reword commit message to our preferred format." - switch "--clean", - description: "Do not rewrite or otherwise modify the commits found in the pulled PR." - switch "--ignore-whitespace", - description: "Silently ignore whitespace discrepancies when applying diffs." - switch "--resolve", - description: "When a patch fails to apply, leave in progress and allow user to resolve, instead "\ - "of aborting." - switch "--branch-okay", - description: "Do not warn if pulling to a branch besides master (useful for testing)." - switch "--no-pbcopy", - description: "Do not copy anything to the system clipboard." - - min_named 1 - hide_from_man_page! - end - end - - def pull - odisabled "brew pull", "gh pr checkout" - end -end diff --git a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb index 5619850d06..dfcb9ea655 100644 --- a/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb +++ b/Library/Homebrew/extend/os/mac/requirements/java_requirement.rb @@ -26,14 +26,14 @@ class JavaRequirement < Requirement end def java_home_cmd - # TODO: enable for all macOS versions and Linux on next minor release + # TODO: disable for all macOS versions and Linux on next minor release # but --version with ranges is broken on Big Sur today. if MacOS.version >= :big_sur && @version&.end_with?("+") odisabled %Q(depends_on java: "#{@version}"), 'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"' end - # odeprecated "depends_on :java", - # 'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"' + odeprecated "depends_on :java", + 'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"' return unless File.executable?("/usr/libexec/java_home") diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index eaed557009..b7db312947 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -113,11 +113,6 @@ class Formula # @private attr_reader :stable - # @private - def devel - odisabled "Formula#devel" - end - # The HEAD {SoftwareSpec} for this {Formula}. # Installed when using `brew install --HEAD`. # This is always installed with the version `HEAD` and taken from the latest @@ -328,11 +323,6 @@ class Formula active_spec == stable end - # @private - def devel? - odisabled "Formula#devel?" - end - # Is the currently active {SoftwareSpec} a {#head} build? # @private def head? @@ -2227,10 +2217,6 @@ class Formula raise "You cannot override Formula#brew in class #{name}" when :test define_method(:test_defined?) { true } - when :patches - odisabled "a Formula#patches definition", "'patch do' block calls" - when :options - odisabled "a Formula#options definition", "'option do' block calls" end end @@ -2274,10 +2260,7 @@ class Formula if args.nil? @licenses else - if args.is_a? Array - odeprecated "`license [...]`", "`license any_of: [...]`" - args = { any_of: args } - end + odisabled "`license [...]`", "`license any_of: [...]`" if args.is_a? Array @licenses = args end end @@ -2463,11 +2446,6 @@ class Formula @stable.instance_eval(&block) end - # @private - def devel - odisabled "'devel' blocks in formulae", "'head' blocks or @-versioned formulae" - end - # @!attribute [w] head # Adds a {.head} {SoftwareSpec}. # This can be installed by passing the `--HEAD` option to allow diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index efe4ef24b4..23a20fbfbe 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -225,12 +225,12 @@ module Formulary def load_file(flags:) if %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?[\w+-.@]+).rb} =~ url # rubocop:disable Style/CaseLikeIf - odisabled "Installation of #{formula_name} from a GitHub commit URL", - "'brew extract #{formula_name}' to stable tap on GitHub" + raise UsageError, "Installation of #{formula_name} from a GitHub commit URL is unsupported! " \ + "'brew extract #{formula_name}' to stable tap on GitHub instead." elsif url.match?(%r{^(https?|ftp)://}) - odisabled "Non-checksummed download of #{name} formula file from an arbitrary URL", - "'brew extract' or 'brew create' and 'brew tap-new' to create a "\ - "formula file in a tap on GitHub" + raise UsageError, "Non-checksummed download of #{name} formula file from an arbitrary URL is unsupported! ", + "'brew extract' or 'brew create' and 'brew tap-new' to create a "\ + "formula file in a tap on GitHub instead." end HOMEBREW_CACHE_FORMULA.mkpath FileUtils.rm_f(path) diff --git a/Library/Homebrew/patch.rb b/Library/Homebrew/patch.rb index 1157c61005..ebdbe3a19d 100644 --- a/Library/Homebrew/patch.rb +++ b/Library/Homebrew/patch.rb @@ -41,14 +41,8 @@ module Patch else {} end.each_pair do |strip, urls| - Array(urls).each do |url| - patch = case url - when :DATA - DATAPatch.new(strip) - else - LegacyPatch.new(strip, url) - end - patches << patch + Array(urls).each do + patches << DATAPatch.new(strip) end end @@ -196,15 +190,3 @@ class ExternalPatch "#<#{self.class.name}: #{strip.inspect} #{url.inspect}>" end end - -# A legacy patch. -# -# Legacy patches have no checksum and are not cached. -# -# @api private -class LegacyPatch < ExternalPatch - def initialize(strip, _url) - odisabled "legacy patches", "'patch do' blocks" - super(strip) - end -end diff --git a/Library/Homebrew/requirements/java_requirement.rb b/Library/Homebrew/requirements/java_requirement.rb index fdee4f4e03..7d7444a553 100644 --- a/Library/Homebrew/requirements/java_requirement.rb +++ b/Library/Homebrew/requirements/java_requirement.rb @@ -34,6 +34,9 @@ class JavaRequirement < Requirement end def initialize(tags = []) + odeprecated "depends_on :java", + '"depends_on "openjdk@11", "depends_on "openjdk@8" or "depends_on "openjdk"' + @version = tags.shift if tags.first&.match?(/^\d/) super(tags) @cask = suggestion.token diff --git a/Library/Homebrew/requirements/macos_requirement.rb b/Library/Homebrew/requirements/macos_requirement.rb index 52b1e84b20..5284acb114 100644 --- a/Library/Homebrew/requirements/macos_requirement.rb +++ b/Library/Homebrew/requirements/macos_requirement.rb @@ -14,16 +14,10 @@ class MacOSRequirement < Requirement attr_reader :comparator, :version def initialize(tags = [], comparator: ">=") - begin - @version = if comparator == "==" && tags.first.respond_to?(:map) - tags.shift.map { |s| MacOS::Version.from_symbol(s) } - else - MacOS::Version.from_symbol(tags.shift) unless tags.empty? - end - rescue MacOSVersionError => e - raise if e.version != :mavericks - - odisabled "depends_on :macos => :mavericks" + @version = if comparator == "==" && tags.first.respond_to?(:map) + tags.shift.map { |s| MacOS::Version.from_symbol(s) } + else + MacOS::Version.from_symbol(tags.shift) unless tags.empty? end @comparator = comparator diff --git a/Library/Homebrew/rubocops/text.rb b/Library/Homebrew/rubocops/text.rb index 5ace971a75..443eab7a58 100644 --- a/Library/Homebrew/rubocops/text.rb +++ b/Library/Homebrew/rubocops/text.rb @@ -95,21 +95,6 @@ module RuboCop end end - find_strings(body_node).each do |n| - next unless regex_match_group(n, /JAVA_HOME/i) - - next if @formula_name.match?(/^openjdk(@|$)/) - - next if find_every_method_call_by_name(body_node, :depends_on).any? do |dependency| - dependency.each_descendant(:str).count.zero? || - regex_match_group(dependency.each_descendant(:str).first, /^openjdk(@|$)/) || - depends_on?(:java) - end - - offending_node(n) - problem "Use `depends_on :java` to set JAVA_HOME" - end - prefix_path(body_node) do |prefix_node, path| next unless match = path.match(%r{^(bin|include|libexec|lib|sbin|share|Frameworks)(?:/| |$)}) diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb index 8b732cae14..5cdbc92261 100644 --- a/Library/Homebrew/tab.rb +++ b/Library/Homebrew/tab.rb @@ -233,23 +233,17 @@ class Tab < OpenStruct end def universal? - odeprecated "Tab#universal?" - include?("universal") + odisabled "Tab#universal?" end def cxx11? - odeprecated "Tab#cxx11?" - include?("c++11") + odisabled "Tab#cxx11?" end def head? spec == :head end - def devel? - odisabled "Tab#devel?" - end - def stable? spec == :stable end @@ -314,10 +308,6 @@ class Tab < OpenStruct Version.create(versions["stable"]) if versions["stable"] end - def devel_version - odisabled "Tab#devel_version" - end - def head_version Version.create(versions["head"]) if versions["head"] end diff --git a/Library/Homebrew/test/cmd/switch_spec.rb b/Library/Homebrew/test/cmd/switch_spec.rb index b568e53000..8ad0ceb4c7 100644 --- a/Library/Homebrew/test/cmd/switch_spec.rb +++ b/Library/Homebrew/test/cmd/switch_spec.rb @@ -6,17 +6,3 @@ require "cmd/shared_examples/args_parse" describe "Homebrew.switch_args" do it_behaves_like "parseable arguments" end - -describe "brew switch", :integration_test do - it "allows switching between Formula versions" do - install_test_formula "testball" - - testball_rack = HOMEBREW_CELLAR/"testball" - FileUtils.cp_r testball_rack/"0.1", testball_rack/"0.2" - - expect { brew "switch", "testball", "0.2" } - .to output(/links created/).to_stdout - .and not_to_output.to_stderr - .and be_a_success - end -end diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index c91b27d04f..e09790157b 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -794,21 +794,19 @@ describe Formula do f1 = formula "f1" do url "f1-1" - depends_on :java depends_on x11: :recommended depends_on xcode: ["1.0", :optional] end stub_formula_loader(f1) - java = JavaRequirement.new x11 = X11Requirement.new([:recommended]) xcode = XcodeRequirement.new(["1.0", :optional]) - expect(Set.new(f1.recursive_requirements)).to eq(Set[java, x11]) + expect(Set.new(f1.recursive_requirements)).to eq(Set[x11]) f1.build = BuildOptions.new(["--with-xcode", "--without-x11"], f1.options) - expect(Set.new(f1.recursive_requirements)).to eq(Set[java, xcode]) + expect(Set.new(f1.recursive_requirements)).to eq(Set[xcode]) f1.build = f1.stable.build f2 = formula "f2" do @@ -817,14 +815,14 @@ describe Formula do depends_on "f1" end - expect(Set.new(f2.recursive_requirements)).to eq(Set[java, x11]) - expect(Set.new(f2.recursive_requirements {})).to eq(Set[java, x11, xcode]) + expect(Set.new(f2.recursive_requirements)).to eq(Set[x11]) + expect(Set.new(f2.recursive_requirements {})).to eq(Set[x11, xcode]) requirements = f2.recursive_requirements do |_dependent, requirement| - Requirement.prune if requirement.is_a?(JavaRequirement) + Requirement.prune if requirement.is_a?(X11Requirement) end - expect(Set.new(requirements)).to eq(Set[x11, xcode]) + expect(Set.new(requirements)).to eq(Set[xcode]) end specify "#to_hash" do diff --git a/Library/Homebrew/test/language/java_spec.rb b/Library/Homebrew/test/language/java_spec.rb index 52613697e0..ccabd4a0f4 100644 --- a/Library/Homebrew/test/language/java_spec.rb +++ b/Library/Homebrew/test/language/java_spec.rb @@ -6,13 +6,13 @@ require "language/java" describe Language::Java do describe "::java_home" do if !OS.mac? || MacOS.version < :big_sur - it "returns valid JAVA_HOME if version is specified", :needs_java do + it "returns valid JAVA_HOME if version is specified", :needs_macos do java_home = described_class.java_home("1.6+") expect(java_home/"bin/java").to be_an_executable end end - it "returns valid JAVA_HOME if version is not specified", :needs_java do + it "returns valid JAVA_HOME if version is not specified", :needs_macos do java_home = described_class.java_home expect(java_home/"bin/java").to be_an_executable end @@ -24,7 +24,7 @@ describe Language::Java do expect(java_home[:JAVA_HOME]).to include("--version blah") end - it "returns java_home path without version if version is not specified", :needs_java do + it "returns java_home path without version if version is not specified", :needs_macos do java_home = described_class.java_home_env expect(java_home[:JAVA_HOME]).not_to include("--version") end @@ -36,7 +36,7 @@ describe Language::Java do expect(java_home[:JAVA_HOME]).to include("--version blah") end - it "returns java_home path without version if version is not specified", :needs_java do + it "returns java_home path without version if version is not specified", :needs_macos do java_home = described_class.overridable_java_home_env expect(java_home[:JAVA_HOME]).not_to include("--version") end diff --git a/Library/Homebrew/test/os/mac/java_requirement_spec.rb b/Library/Homebrew/test/os/mac/java_requirement_spec.rb deleted file mode 100644 index 20ea5687b6..0000000000 --- a/Library/Homebrew/test/os/mac/java_requirement_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "requirements/java_requirement" -require "fileutils" - -describe JavaRequirement do - subject { described_class.new(%w[1.8]) } - - let(:java_home) { mktmpdir } - - before do - FileUtils.mkdir java_home/"bin" - FileUtils.touch java_home/"bin/java" - allow(subject).to receive(:preferred_java).and_return(java_home/"bin/java") - end - - specify "Apple Java environment" do - expect(subject).to be_satisfied - - expect(ENV).to receive(:prepend_path) - expect(ENV).to receive(:append_to_cflags) - - subject.modify_build_environment - expect(ENV["JAVA_HOME"]).to eq(java_home.to_s) - end - - specify "Oracle Java environment" do - expect(subject).to be_satisfied - - FileUtils.mkdir java_home/"include" - expect(ENV).to receive(:prepend_path) - expect(ENV).to receive(:append_to_cflags).twice - - subject.modify_build_environment - expect(ENV["JAVA_HOME"]).to eq(java_home.to_s) - end -end diff --git a/Library/Homebrew/test/requirements/java_requirement_spec.rb b/Library/Homebrew/test/requirements/java_requirement_spec.rb deleted file mode 100644 index a33c25928c..0000000000 --- a/Library/Homebrew/test/requirements/java_requirement_spec.rb +++ /dev/null @@ -1,159 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "requirements/java_requirement" - -describe JavaRequirement do - subject { described_class.new([]) } - - before do - ENV["JAVA_HOME"] = nil - end - - describe "#initialize" do - it "parses '1.8' tag correctly" do - req = described_class.new(["1.8"]) - expect(req.display_s).to eq("Java = 1.8") - end - - it "parses '9' tag correctly" do - req = described_class.new(["9"]) - expect(req.display_s).to eq("Java = 9") - end - - it "parses '9+' tag correctly" do - req = described_class.new(["9+"]) - expect(req.display_s).to eq("Java >= 9") - end - - it "parses '11' tag correctly" do - req = described_class.new(["11"]) - expect(req.display_s).to eq("Java = 11") - end - - it "parses bogus tag correctly" do - req = described_class.new(["bogus1.8"]) - expect(req.display_s).to eq("Java") - end - end - - describe "#message" do - its(:message) { is_expected.to match(/Java is required for this software./) } - end - - describe "#inspect" do - subject { described_class.new(%w[1.7+]) } - - its(:inspect) { is_expected.to eq('#') } - end - - describe "#display_s" do - context "without specific version" do - its(:display_s) { is_expected.to eq("Java") } - end - - context "with version 1.8" do - subject { described_class.new(%w[1.8]) } - - its(:display_s) { is_expected.to eq("Java = 1.8") } - end - - context "with version 1.8+" do - subject { described_class.new(%w[1.8+]) } - - its(:display_s) { is_expected.to eq("Java >= 1.8") } - end - end - - describe "#satisfied?" do - subject(:requirement) { described_class.new(%w[1.8]) } - - if !OS.mac? || MacOS.version < :big_sur - it "returns false if no `java` executable can be found" do - allow(File).to receive(:executable?).and_return(false) - expect(requirement).not_to be_satisfied - end - end - - it "returns true if #preferred_java returns a path" do - allow(requirement).to receive(:preferred_java).and_return(Pathname.new("/usr/bin/java")) - expect(requirement).to be_satisfied - end - - context "when #possible_javas contains paths" do - let(:path) { mktmpdir } - let(:java) { path/"java" } - - def setup_java_with_version(version) - IO.write java, <<~SH - #!/bin/sh - echo 'java version "#{version}"' 1>&2 - SH - FileUtils.chmod "+x", java - end - - before do - allow(requirement).to receive(:possible_javas).and_return([java]) - end - - context "and 1.7 is required" do - subject(:requirement) { described_class.new(%w[1.7]) } - - it "returns false if all are lower" do - setup_java_with_version "1.6.0_5" - expect(requirement).not_to be_satisfied - end - - it "returns true if one is equal" do - setup_java_with_version "1.7.0_5" - expect(requirement).to be_satisfied - end - - it "returns false if all are higher" do - setup_java_with_version "1.8.0_5" - expect(requirement).not_to be_satisfied - end - end - - context "and 1.7+ is required" do - subject(:requirement) { described_class.new(%w[1.7+]) } - - it "returns false if all are lower" do - setup_java_with_version "1.6.0_5" - expect(requirement).not_to be_satisfied - end - - it "returns true if one is equal" do - setup_java_with_version "1.7.0_5" - expect(requirement).to be_satisfied - end - - it "returns true if one is higher" do - setup_java_with_version "1.8.0_5" - expect(requirement).to be_satisfied - end - end - end - end - - describe "#suggestion" do - context "without specific version" do - its(:suggestion) { is_expected.to match(/brew cask install adoptopenjdk/) } - its(:cask) { is_expected.to eq("adoptopenjdk") } - end - - context "with version 1.8" do - subject { described_class.new(%w[1.8]) } - - its(:suggestion) { is_expected.to match(%r{brew cask install homebrew/cask-versions/adoptopenjdk8}) } - its(:cask) { is_expected.to eq("homebrew/cask-versions/adoptopenjdk8") } - end - - context "with version 1.8+" do - subject { described_class.new(%w[1.8+]) } - - its(:suggestion) { is_expected.to match(/brew cask install adoptopenjdk/) } - its(:cask) { is_expected.to eq("adoptopenjdk") } - end - end -end diff --git a/Library/Homebrew/test/rubocops/text_spec.rb b/Library/Homebrew/test/rubocops/text_spec.rb index c308451b19..63c49df4f8 100644 --- a/Library/Homebrew/test/rubocops/text_spec.rb +++ b/Library/Homebrew/test/rubocops/text_spec.rb @@ -250,61 +250,6 @@ describe RuboCop::Cop::FormulaAudit::Text do RUBY end - it "When using JAVA_HOME without a java dependency" do - expect_offense(<<~RUBY) - class Foo < Formula - def install - ohai "JAVA_HOME" - ^^^^^^^^^^^ Use `depends_on :java` to set JAVA_HOME - end - end - RUBY - end - - it "When using JAVA_HOME with an openjdk dependency" do - expect_no_offenses(<<~RUBY) - class Foo < Formula - depends_on "openjdk" - def install - ohai "JAVA_HOME" - end - end - RUBY - end - - it "When using JAVA_HOME with an openjdk build dependency" do - expect_no_offenses(<<~RUBY) - class Foo < Formula - depends_on "openjdk" => :build - def install - ohai "JAVA_HOME" - end - end - RUBY - end - - it "When using JAVA_HOME with a java dependency" do - expect_no_offenses(<<~RUBY) - class Foo < Formula - depends_on :java - def install - ohai "JAVA_HOME" - end - end - RUBY - end - - it "When using JAVA_HOME with a java build dependency" do - expect_no_offenses(<<~RUBY) - class Foo < Formula - depends_on :java => :build - def install - ohai "JAVA_HOME" - end - end - RUBY - end - it "When using `prefix + \"bin\"` instead of `bin`" do expect_offense(<<~RUBY) class Foo < Formula diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index a235b77d74..f4553f5c16 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -96,9 +96,7 @@ module GitHub return unless Homebrew::EnvConfig.github_api_username return unless Homebrew::EnvConfig.github_api_password - odeprecated "the GitHub API with HOMEBREW_GITHUB_API_PASSWORD", "HOMEBREW_GITHUB_API_TOKEN" - - [Homebrew::EnvConfig.github_api_password, Homebrew::EnvConfig.github_api_username] + odisabled "the GitHub API with HOMEBREW_GITHUB_API_PASSWORD", "HOMEBREW_GITHUB_API_TOKEN" end def keychain_username_password diff --git a/completions/internal_commands_list.txt b/completions/internal_commands_list.txt index 9c91e9f1f3..13cf54e93a 100644 --- a/completions/internal_commands_list.txt +++ b/completions/internal_commands_list.txt @@ -68,7 +68,6 @@ pr-publish pr-pull pr-upload prof -pull readall reinstall release-notes diff --git a/docs/Manpage.md b/docs/Manpage.md index 586a1639b7..5366a41309 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1004,17 +1004,6 @@ Build bottles for these formulae with GitHub Actions. * `--upload`: Upload built bottles to Bintray. -### `diy` [*`options`*] - -Automatically determine the installation prefix for non-Homebrew software. -Using the output from this command, you can install your own software into -the Cellar and then link it into Homebrew's prefix with `brew link`. - -* `--name`: - Explicitly set the *`name`* of the package being installed. -* `--version`: - Explicitly set the *`version`* of the package being installed. - ### `edit` [*`formula`*|*`cask`*] Open a *`formula`* or *`cask`* in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, @@ -1098,6 +1087,17 @@ Generate Homebrew's manpages. * `--link`: This is now done automatically by `brew update`. +### `mirror` *`formula`* + +Reupload the stable URL of a formula to Bintray for use as a mirror. + +* `--bintray-org`: + Upload to the specified Bintray organisation (default: `homebrew`). +* `--bintray-repo`: + Upload to the specified Bintray repository (default: `mirror`). +* `--no-publish`: + Upload to Bintray, but don't publish. + ### `pr-automerge` [*`options`*] Find pull requests that can be automatically merged using `brew pr-publish`. diff --git a/manpages/brew.1 b/manpages/brew.1 index 0b237b463f..143c5fdf95 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1413,17 +1413,6 @@ Dispatch specified workflow (default: \fBdispatch\-build\-bottle\.yml\fR)\. \fB\-\-upload\fR Upload built bottles to Bintray\. . -.SS "\fBdiy\fR [\fIoptions\fR]" -Automatically determine the installation prefix for non\-Homebrew software\. Using the output from this command, you can install your own software into the Cellar and then link it into Homebrew\'s prefix with \fBbrew link\fR\. -. -.TP -\fB\-\-name\fR -Explicitly set the \fIname\fR of the package being installed\. -. -.TP -\fB\-\-version\fR -Explicitly set the \fIversion\fR of the package being installed\. -. .SS "\fBedit\fR [\fIformula\fR|\fIcask\fR]" Open a \fIformula\fR or \fIcask\fR in the editor set by \fBEDITOR\fR or \fBHOMEBREW_EDITOR\fR, or open the Homebrew repository for editing if no formula is provided\. . @@ -1523,6 +1512,21 @@ Return a failing status code if changes are detected in the manpage outputs\. Th \fB\-\-link\fR This is now done automatically by \fBbrew update\fR\. . +.SS "\fBmirror\fR \fIformula\fR" +Reupload the stable URL of a formula to Bintray for use as a mirror\. +. +.TP +\fB\-\-bintray\-org\fR +Upload to the specified Bintray organisation (default: \fBhomebrew\fR)\. +. +.TP +\fB\-\-bintray\-repo\fR +Upload to the specified Bintray repository (default: \fBmirror\fR)\. +. +.TP +\fB\-\-no\-publish\fR +Upload to Bintray, but don\'t publish\. +. .SS "\fBpr\-automerge\fR [\fIoptions\fR]" Find pull requests that can be automatically merged using \fBbrew pr\-publish\fR\. . From c32415529532369c6fffdd34c95da1ee21546f87 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Tue, 24 Nov 2020 18:26:15 +0100 Subject: [PATCH 30/39] Add debug information for empty BOM error. --- Library/Homebrew/unpack_strategy/dmg.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Library/Homebrew/unpack_strategy/dmg.rb b/Library/Homebrew/unpack_strategy/dmg.rb index db6f3285d5..970811bd5c 100644 --- a/Library/Homebrew/unpack_strategy/dmg.rb +++ b/Library/Homebrew/unpack_strategy/dmg.rb @@ -91,8 +91,10 @@ module UnpackStrategy Tempfile.open(["", ".bom"]) do |bomfile| bomfile.close + bom = path.bom + Tempfile.open(["", ".list"]) do |filelist| - filelist.puts(path.bom) + filelist.puts(bom) filelist.close system_command! "mkbom", @@ -100,9 +102,14 @@ module UnpackStrategy verbose: verbose end - system_command! "ditto", - args: ["--bom", bomfile.path, "--", path, unpack_dir], - verbose: verbose + result = system_command! "ditto", + args: ["--bom", bomfile.path, "--", path, unpack_dir], + verbose: verbose + + odebug "BOM contents:", bom + if result.stderr.include?("contains no files, nothing copied") + odebug "Directory contents:", Pathname.glob(path/"**/*", File::FNM_DOTMATCH).map(&:to_s).join("\n") + end FileUtils.chmod "u+w", Pathname.glob(unpack_dir/"**/*", File::FNM_DOTMATCH).reject(&:symlink?) end From 8e670995f8907f3b47069def7181dccc33fe2f06 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Wed, 18 Nov 2020 02:25:55 -0500 Subject: [PATCH 31/39] migrate automatic python resource list to Homebrew/core --- .../dev-cmd/update-python-resources.rb | 16 ++- Library/Homebrew/utils/pypi.rb | 122 ++++++++++++------ 2 files changed, 97 insertions(+), 41 deletions(-) diff --git a/Library/Homebrew/dev-cmd/update-python-resources.rb b/Library/Homebrew/dev-cmd/update-python-resources.rb index ee3cd4be19..736268b875 100644 --- a/Library/Homebrew/dev-cmd/update-python-resources.rb +++ b/Library/Homebrew/dev-cmd/update-python-resources.rb @@ -26,6 +26,14 @@ module Homebrew flag "--version=", description: "Use the specified when finding resources for . "\ "If no version is specified, the current version for will be used." + flag "--package-name=", + depends_on: "--version", + description: "Use the specified when finding resources for . "\ + "If no package name is specified, it will be inferred from the formula's stable URL." + comma_array "--extra-packages=", + description: "Include these additional packages when finding resources." + comma_array "--exclude-packages=", + description: "Exclude these packages when finding resources." min_named :formula end @@ -35,7 +43,13 @@ module Homebrew args = update_python_resources_args.parse args.named.to_formulae.each do |formula| - PyPI.update_python_resources! formula, args.version, print_only: args.print_only?, silent: args.silent?, + PyPI.update_python_resources! formula, + version: args.version, + package_name: args.package_name, + extra_packages: args.extra_packages, + exclude_packages: args.exclude_packages, + print_only: args.print_only?, + silent: args.silent?, ignore_non_pypi_packages: args.ignore_non_pypi_packages? end end diff --git a/Library/Homebrew/utils/pypi.rb b/Library/Homebrew/utils/pypi.rb index 6f91f31b57..292f827ab0 100644 --- a/Library/Homebrew/utils/pypi.rb +++ b/Library/Homebrew/utils/pypi.rb @@ -10,18 +10,6 @@ module PyPI PYTHONHOSTED_URL_PREFIX = "https://files.pythonhosted.org/packages/" private_constant :PYTHONHOSTED_URL_PREFIX - AUTOMATIC_RESOURCE_UPDATE_BLOCKLIST = %w[ - ansible - ansible@2.8 - cloudformation-cli - diffoscope - dxpy - ipython - molecule - salt - ].freeze - private_constant :AUTOMATIC_RESOURCE_UPDATE_BLOCKLIST - @pipgrip_installed = nil def url_to_pypi_package_name(url) @@ -40,7 +28,11 @@ module PyPI # Get name, URL and SHA-256 checksum for a given PyPI package. def get_pypi_info(package, version) - metadata_url = "https://pypi.org/pypi/#{package}/#{version}/json" + metadata_url = if version.present? + "https://pypi.org/pypi/#{package}/#{version}/json" + else + "https://pypi.org/pypi/#{package}/json" + end out, _, status = curl_output metadata_url, "--location" return unless status.success? @@ -58,17 +50,38 @@ module PyPI end # Return true if resources were checked (even if no change). - def update_python_resources!(formula, version = nil, print_only: false, silent: false, - ignore_non_pypi_packages: false) + def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil, + print_only: false, silent: false, ignore_non_pypi_packages: false) - if !print_only && AUTOMATIC_RESOURCE_UPDATE_BLOCKLIST.include?(formula.full_name) - odie "The resources for \"#{formula.name}\" need special attention. Please update them manually." - return + auto_update_list = formula.tap.audit_exceptions[:automatic_resource_update_list] + if package_name.blank? && extra_packages.blank? && !print_only && + auto_update_list.present? && auto_update_list.key?(formula.full_name) + + list_entry = auto_update_list[formula.full_name] + case list_entry + when false + odie "The resources for \"#{formula.name}\" need special attention. Please update them manually." + when String + package_name = list_entry + when Hash + package_name = list_entry["package_name"] + extra_packages = list_entry["extra_packages"] + exclude_packages = list_entry["exclude_packages"] + end end - pypi_name = url_to_pypi_package_name formula.stable.url + package_name ||= url_to_pypi_package_name formula.stable.url + version ||= formula.version + extra_packages ||= [] + exclude_packages ||= [] - if pypi_name.nil? + # opoo "package_name: #{package_name}" + # opoo "version: #{version}" + # opoo "extra_packages: #{extra_packages}" + # opoo "exclude_packages: #{exclude_packages}" + # odie "" + + if package_name.nil? return if ignore_non_pypi_packages odie <<~EOS @@ -77,11 +90,24 @@ module PyPI EOS end - version ||= formula.version + input_package_names = { package_name => version } + extra_packages.each do |extra| + extra_name, extra_version = extra.split "==" - if get_pypi_info(pypi_name, version).blank? - odie "\"#{pypi_name}\" at version #{version} is not available on PyPI." unless ignore_non_pypi_packages - return + if input_package_names.key?(extra_name) && input_package_names[extra_name] != extra_version + odie "Conflicting versions specified for the `#{extra_name}` package: "\ + "#{input_package_names[extra_name]}, #{extra_version}" + end + + input_package_names[extra_name] = extra_version + end + + input_package_names.each do |name, package_version| + name = name.split("[").first + next if get_pypi_info(name, package_version).present? + + version_string = " at version #{package_version}" if package_version.present? + odie "\"#{name}\"#{version_string} is not available on PyPI." unless ignore_non_pypi_packages end non_pypi_resources = formula.resources.reject do |resource| @@ -95,27 +121,43 @@ module PyPI @pipgrip_installed ||= Formula["pipgrip"].any_version_installed? odie '"pipgrip" must be installed (`brew install pipgrip`)' unless @pipgrip_installed - ohai "Retrieving PyPI dependencies for \"#{pypi_name}==#{version}\"..." if !print_only && !silent - pipgrip_output = Utils.popen_read Formula["pipgrip"].bin/"pipgrip", "--json", "--no-cache-dir", - "#{pypi_name}==#{version}" - unless $CHILD_STATUS.success? - odie <<~EOS - Unable to determine dependencies for \"#{pypi_name}\" because of a failure when running - `pipgrip --json --no-cache-dir #{pypi_name}==#{version}`. - Please update the resources for \"#{formula.name}\" manually. - EOS - end + found_packages = {} + input_package_names.each do |name, package_version| + pypi_package_string = if package_version.present? + "#{name}==#{package_version}" + else + name + end - packages = JSON.parse(pipgrip_output).sort.to_h + ohai "Retrieving PyPI dependencies for \"#{pypi_package_string}\"..." if !print_only && !silent + pipgrip_output = Utils.popen_read Formula["pipgrip"].bin/"pipgrip", "--json", "--no-cache-dir", + pypi_package_string + unless $CHILD_STATUS.success? + odie <<~EOS + Unable to determine dependencies for \"#{name}\" because of a failure when running + `pipgrip --json --no-cache-dir #{pypi_package_string}`. + Please update the resources for \"#{formula.name}\" manually. + EOS + end + + found_packages.merge!(JSON.parse(pipgrip_output).sort.to_h) do |conflicting_package, old_version, new_version| + next old_version if old_version == new_version + + odie "Conflicting versions found for the `#{conflicting_package}` resource: #{old_version}, #{new_version}" + end + end # Remove extra packages that may be included in pipgrip output - exclude_list = %W[#{pypi_name.downcase} argparse pip setuptools wheel wsgiref] - packages.delete_if do |package| - exclude_list.include? package - end + exclude_list = %W[#{package_name.downcase} argparse pip setuptools wheel wsgiref] + found_packages.delete_if { |package| exclude_list.include? package } new_resource_blocks = "" - packages.each do |package, package_version| + found_packages.each do |package, package_version| + if exclude_packages.include? package + ohai "Excluding \"#{package}==#{package_version}\"" if !print_only && !silent + next + end + ohai "Getting PyPI info for \"#{package}==#{package_version}\"" if !print_only && !silent name, url, checksum = get_pypi_info package, package_version # Fail if unable to find name, url or checksum for any resource From b1d907291b7150b7a243c9a62ee22f3e9c0f2770 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Wed, 18 Nov 2020 02:48:05 -0500 Subject: [PATCH 32/39] update man pages --- docs/Manpage.md | 6 ++++++ manpages/brew.1 | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/docs/Manpage.md b/docs/Manpage.md index 014d4413dd..291381b289 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1352,6 +1352,12 @@ Update versions for PyPI resource blocks in *`formula`*. Don't fail if *`formula`* is not a PyPI package. * `--version`: Use the specified *`version`* when finding resources for *`formula`*. If no version is specified, the current version for *`formula`* will be used. +* `--package-name`: + Use the specified *`package-name`* when finding resources for *`formula`*. If no package name is specified, it will be inferred from the formula's stable URL. +* `--extra-packages`: + Include these additional packages when finding resources. +* `--exclude-packages`: + Exclude these packages when finding resources. ### `update-test` [*`options`*] diff --git a/manpages/brew.1 b/manpages/brew.1 index 8fa25bf1ae..e700050a57 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1884,6 +1884,18 @@ Don\'t fail if \fIformula\fR is not a PyPI package\. \fB\-\-version\fR Use the specified \fIversion\fR when finding resources for \fIformula\fR\. If no version is specified, the current version for \fIformula\fR will be used\. . +.TP +\fB\-\-package\-name\fR +Use the specified \fIpackage\-name\fR when finding resources for \fIformula\fR\. If no package name is specified, it will be inferred from the formula\'s stable URL\. +. +.TP +\fB\-\-extra\-packages\fR +Include these additional packages when finding resources\. +. +.TP +\fB\-\-exclude\-packages\fR +Exclude these packages when finding resources\. +. .SS "\fBupdate\-test\fR [\fIoptions\fR]" Run a test of \fBbrew update\fR with a new repository clone\. If no options are passed, use \fBorigin/master\fR as the start commit\. . From 51a1b7c9e1b39e19cc93cb9e40017218a1d2d8cd Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 20 Nov 2020 00:55:21 -0500 Subject: [PATCH 33/39] move pypi list to tap formula_lists directory --- .../dev-cmd/update-python-resources.rb | 1 - Library/Homebrew/tap.rb | 49 ++++++++++++----- Library/Homebrew/tap_auditor.rb | 55 +++++++++++-------- Library/Homebrew/utils/pypi.rb | 27 ++++----- 4 files changed, 76 insertions(+), 56 deletions(-) diff --git a/Library/Homebrew/dev-cmd/update-python-resources.rb b/Library/Homebrew/dev-cmd/update-python-resources.rb index 736268b875..936dad5aba 100644 --- a/Library/Homebrew/dev-cmd/update-python-resources.rb +++ b/Library/Homebrew/dev-cmd/update-python-resources.rb @@ -27,7 +27,6 @@ module Homebrew description: "Use the specified when finding resources for . "\ "If no version is specified, the current version for will be used." flag "--package-name=", - depends_on: "--version", description: "Use the specified when finding resources for . "\ "If no package name is specified, it will be inferred from the formula's stable URL." comma_array "--extra-packages=", diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index d4a33d8ab7..02e60e15cb 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -21,11 +21,13 @@ class Tap HOMEBREW_TAP_FORMULA_RENAMES_FILE = "formula_renames.json" HOMEBREW_TAP_MIGRATIONS_FILE = "tap_migrations.json" HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR = "audit_exceptions" + HOMEBREW_TAP_FORMULA_LISTS_DIR = "formula_lists" HOMEBREW_TAP_JSON_FILES = %W[ #{HOMEBREW_TAP_FORMULA_RENAMES_FILE} #{HOMEBREW_TAP_MIGRATIONS_FILE} #{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*.json + #{HOMEBREW_TAP_FORMULA_LISTS_DIR}/*.json ].freeze def self.fetch(*args) @@ -112,6 +114,7 @@ class Tap @formula_renames = nil @tap_migrations = nil @audit_exceptions = nil + @formula_lists = nil @config = nil remove_instance_variable(:@private) if instance_variable_defined?(:@private) end @@ -560,22 +563,12 @@ class Tap # Hash with audit exceptions def audit_exceptions - @audit_exceptions = {} + @audit_exceptions = read_formula_list_directory HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR + end - Pathname.glob(path/HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR/"*").each do |exception_file| - list_name = exception_file.basename.to_s.chomp(".json").to_sym - list_contents = begin - JSON.parse exception_file.read - rescue JSON::ParserError - opoo "#{exception_file} contains invalid JSON" - end - - next if list_contents.nil? - - @audit_exceptions[list_name] = list_contents - end - - @audit_exceptions + # Hash with formula lists + def formula_lists + @formula_lists = read_formula_list_directory HOMEBREW_TAP_FORMULA_LISTS_DIR end def ==(other) @@ -636,6 +629,25 @@ class Tap end end end + + def read_formula_list_directory(directory) + list = {} + + Pathname.glob(path/directory/"*").each do |exception_file| + list_name = exception_file.basename.to_s.chomp(".json").to_sym + list_contents = begin + JSON.parse exception_file.read + rescue JSON::ParserError + opoo "#{exception_file} contains invalid JSON" + end + + next if list_contents.nil? + + list[list_name] = list_contents + end + + list + end end # A specialized {Tap} class for the core formulae. @@ -739,6 +751,13 @@ class CoreTap < Tap end end + def formula_lists + @formula_lists ||= begin + self.class.ensure_installed! + super + end + end + # @private def formula_file_to_name(file) file.basename(".rb").to_s diff --git a/Library/Homebrew/tap_auditor.rb b/Library/Homebrew/tap_auditor.rb index d8294815f2..17be78d11c 100644 --- a/Library/Homebrew/tap_auditor.rb +++ b/Library/Homebrew/tap_auditor.rb @@ -15,13 +15,14 @@ module Homebrew @name = tap.name @path = tap.path @tap_audit_exceptions = tap.audit_exceptions + @tap_formula_lists = tap.formula_lists @problems = [] end sig { void } def audit audit_json_files - audit_tap_audit_exceptions + audit_tap_formula_lists end sig { void } @@ -35,32 +36,38 @@ module Homebrew end sig { void } - def audit_tap_audit_exceptions - @tap_audit_exceptions.each do |list_name, formula_names| - unless [Hash, Array].include? formula_names.class + def audit_tap_formula_lists + tap_lists = { + audit_exceptions: @tap_audit_exceptions, + formula_lists: @tap_formula_lists, + } + tap_lists.each do |list_directory, list| + list.each do |list_name, formula_names| + unless [Hash, Array].include? formula_names.class + problem <<~EOS + #{list_directory}/#{list_name}.json should contain a JSON array + of formula names or a JSON object mapping formula names to values + EOS + next + end + + formula_names = formula_names.keys if formula_names.is_a? Hash + + invalid_formulae = [] + formula_names.each do |name| + invalid_formulae << name if Formula[name].tap != @name + rescue FormulaUnavailableError + invalid_formulae << name + end + + next if invalid_formulae.empty? + problem <<~EOS - audit_exceptions/#{list_name}.json should contain a JSON array - of formula names or a JSON object mapping formula names to values + #{list_directory}/#{list_name}.json references + formulae that are not found in the #{@name} tap. + Invalid formulae: #{invalid_formulae.join(", ")} EOS - next end - - formula_names = formula_names.keys if formula_names.is_a? Hash - - invalid_formulae = [] - formula_names.each do |name| - invalid_formulae << name if Formula[name].tap != @name - rescue FormulaUnavailableError - invalid_formulae << name - end - - next if invalid_formulae.empty? - - problem <<~EOS - audit_exceptions/#{list_name}.json references - formulae that are not found in the #{@name} tap. - Invalid formulae: #{invalid_formulae.join(", ")} - EOS end end diff --git a/Library/Homebrew/utils/pypi.rb b/Library/Homebrew/utils/pypi.rb index 292f827ab0..ad75aa6f0e 100644 --- a/Library/Homebrew/utils/pypi.rb +++ b/Library/Homebrew/utils/pypi.rb @@ -26,8 +26,9 @@ module PyPI url end - # Get name, URL and SHA-256 checksum for a given PyPI package. - def get_pypi_info(package, version) + # Get name, URL, SHA-256 checksum, and latest version for a given PyPI package. + def get_pypi_info(package, version = nil) + package = package.split("[").first metadata_url = if version.present? "https://pypi.org/pypi/#{package}/#{version}/json" else @@ -46,15 +47,15 @@ module PyPI sdist = json["urls"].find { |url| url["packagetype"] == "sdist" } return json["info"]["name"] if sdist.nil? - [json["info"]["name"], sdist["url"], sdist["digests"]["sha256"]] + [json["info"]["name"], sdist["url"], sdist["digests"]["sha256"], json["info"]["version"]] end # Return true if resources were checked (even if no change). def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil, print_only: false, silent: false, ignore_non_pypi_packages: false) - auto_update_list = formula.tap.audit_exceptions[:automatic_resource_update_list] - if package_name.blank? && extra_packages.blank? && !print_only && + auto_update_list = formula.tap.formula_lists[:pypi_automatic_resource_update_list] + if package_name.blank? && extra_packages.blank? && exclude_packages.blank? && !print_only && auto_update_list.present? && auto_update_list.key?(formula.full_name) list_entry = auto_update_list[formula.full_name] @@ -70,18 +71,12 @@ module PyPI end end + version ||= formula.version if package_name.blank? package_name ||= url_to_pypi_package_name formula.stable.url - version ||= formula.version extra_packages ||= [] exclude_packages ||= [] - # opoo "package_name: #{package_name}" - # opoo "version: #{version}" - # opoo "extra_packages: #{extra_packages}" - # opoo "exclude_packages: #{exclude_packages}" - # odie "" - - if package_name.nil? + if package_name.blank? return if ignore_non_pypi_packages odie <<~EOS @@ -140,7 +135,7 @@ module PyPI EOS end - found_packages.merge!(JSON.parse(pipgrip_output).sort.to_h) do |conflicting_package, old_version, new_version| + found_packages.merge!(JSON.parse(pipgrip_output).to_h) do |conflicting_package, old_version, new_version| next old_version if old_version == new_version odie "Conflicting versions found for the `#{conflicting_package}` resource: #{old_version}, #{new_version}" @@ -148,11 +143,11 @@ module PyPI end # Remove extra packages that may be included in pipgrip output - exclude_list = %W[#{package_name.downcase} argparse pip setuptools wheel wsgiref] + exclude_list = %W[#{package_name.split("[").first.downcase} argparse pip setuptools wheel wsgiref] found_packages.delete_if { |package| exclude_list.include? package } new_resource_blocks = "" - found_packages.each do |package, package_version| + found_packages.sort.each do |package, package_version| if exclude_packages.include? package ohai "Excluding \"#{package}==#{package_version}\"" if !print_only && !silent next From fac2bd8843f6d959e2566a872d1863abf52d6b62 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 20 Nov 2020 01:55:34 -0500 Subject: [PATCH 34/39] use auto update list when --print-only is passed --- Library/Homebrew/utils/pypi.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/utils/pypi.rb b/Library/Homebrew/utils/pypi.rb index ad75aa6f0e..1822951775 100644 --- a/Library/Homebrew/utils/pypi.rb +++ b/Library/Homebrew/utils/pypi.rb @@ -55,13 +55,15 @@ module PyPI print_only: false, silent: false, ignore_non_pypi_packages: false) auto_update_list = formula.tap.formula_lists[:pypi_automatic_resource_update_list] - if package_name.blank? && extra_packages.blank? && exclude_packages.blank? && !print_only && - auto_update_list.present? && auto_update_list.key?(formula.full_name) + if auto_update_list.present? && auto_update_list.key?(formula.full_name) && + package_name.blank? && extra_packages.blank? && exclude_packages.blank? list_entry = auto_update_list[formula.full_name] case list_entry when false - odie "The resources for \"#{formula.name}\" need special attention. Please update them manually." + unless print_only + odie "The resources for \"#{formula.name}\" need special attention. Please update them manually." + end when String package_name = list_entry when Hash From 20de58b5ae473939e9a39d4e79c3a6f7601d6bf1 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 20 Nov 2020 09:27:42 -0500 Subject: [PATCH 35/39] bump-formula-pr: use new update_python_resources! signature --- Library/Homebrew/dev-cmd/bump-formula-pr.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 4e648874f2..dffc4dcdf3 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -336,7 +336,7 @@ module Homebrew end unless args.dry_run? - resources_checked = PyPI.update_python_resources! formula, new_formula_version, + resources_checked = PyPI.update_python_resources! formula, version: new_formula_version, silent: args.quiet?, ignore_non_pypi_packages: true end From ee47b863c49ee151fd491f5e687460198ae256fe Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Fri, 20 Nov 2020 18:14:45 -0500 Subject: [PATCH 36/39] move mapping from formula_lists to pypi_formula_mappings --- Library/Homebrew/tap.rb | 41 ++++++++++------- Library/Homebrew/tap_auditor.rb | 81 +++++++++++++++++---------------- Library/Homebrew/utils/pypi.rb | 2 +- 3 files changed, 69 insertions(+), 55 deletions(-) diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 02e60e15cb..0022617249 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -21,13 +21,13 @@ class Tap HOMEBREW_TAP_FORMULA_RENAMES_FILE = "formula_renames.json" HOMEBREW_TAP_MIGRATIONS_FILE = "tap_migrations.json" HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR = "audit_exceptions" - HOMEBREW_TAP_FORMULA_LISTS_DIR = "formula_lists" + HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS = "pypi_formula_mappings.json" HOMEBREW_TAP_JSON_FILES = %W[ #{HOMEBREW_TAP_FORMULA_RENAMES_FILE} #{HOMEBREW_TAP_MIGRATIONS_FILE} #{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*.json - #{HOMEBREW_TAP_FORMULA_LISTS_DIR}/*.json + #{HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS} ].freeze def self.fetch(*args) @@ -114,7 +114,7 @@ class Tap @formula_renames = nil @tap_migrations = nil @audit_exceptions = nil - @formula_lists = nil + @pypi_formula_mappings = nil @config = nil remove_instance_variable(:@private) if instance_variable_defined?(:@private) end @@ -562,13 +562,15 @@ class Tap end # Hash with audit exceptions + sig { returns(Hash) } def audit_exceptions - @audit_exceptions = read_formula_list_directory HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR + @audit_exceptions = read_formula_list_directory "#{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*" end - # Hash with formula lists - def formula_lists - @formula_lists = read_formula_list_directory HOMEBREW_TAP_FORMULA_LISTS_DIR + # Hash with pypi formula mappings + sig { returns(Hash) } + def pypi_formula_mappings + @pypi_formula_mappings = read_formula_list path/HOMEBREW_TAP_PYPI_FORMULA_MAPPINGS end def ==(other) @@ -630,18 +632,25 @@ class Tap end end + sig { params(file: Pathname).returns(Hash) } + def read_formula_list(file) + JSON.parse file.read + rescue JSON::ParserError + opoo "#{file} contains invalid JSON" + {} + rescue Errno::ENOENT + {} + end + + sig { params(directory: String).returns(Hash) } def read_formula_list_directory(directory) list = {} - Pathname.glob(path/directory/"*").each do |exception_file| + Pathname.glob(path/directory).each do |exception_file| list_name = exception_file.basename.to_s.chomp(".json").to_sym - list_contents = begin - JSON.parse exception_file.read - rescue JSON::ParserError - opoo "#{exception_file} contains invalid JSON" - end + list_contents = read_formula_list exception_file - next if list_contents.nil? + next if list_contents.blank? list[list_name] = list_contents end @@ -751,8 +760,8 @@ class CoreTap < Tap end end - def formula_lists - @formula_lists ||= begin + def pypi_formula_mappings + @pypi_formula_mappings ||= begin self.class.ensure_installed! super end diff --git a/Library/Homebrew/tap_auditor.rb b/Library/Homebrew/tap_auditor.rb index 17be78d11c..5936980919 100644 --- a/Library/Homebrew/tap_auditor.rb +++ b/Library/Homebrew/tap_auditor.rb @@ -8,15 +8,15 @@ module Homebrew class TapAuditor extend T::Sig - attr_reader :name, :path, :tap_audit_exceptions, :problems + attr_reader :name, :path, :tap_audit_exceptions, :tap_pypi_formula_mappings, :problems sig { params(tap: Tap, strict: T.nilable(T::Boolean)).void } def initialize(tap, strict:) - @name = tap.name - @path = tap.path - @tap_audit_exceptions = tap.audit_exceptions - @tap_formula_lists = tap.formula_lists - @problems = [] + @name = tap.name + @path = tap.path + @tap_audit_exceptions = tap.audit_exceptions + @tap_pypi_formula_mappings = tap.pypi_formula_mappings + @problems = [] end sig { void } @@ -37,43 +37,48 @@ module Homebrew sig { void } def audit_tap_formula_lists - tap_lists = { - audit_exceptions: @tap_audit_exceptions, - formula_lists: @tap_formula_lists, - } - tap_lists.each do |list_directory, list| - list.each do |list_name, formula_names| - unless [Hash, Array].include? formula_names.class - problem <<~EOS - #{list_directory}/#{list_name}.json should contain a JSON array - of formula names or a JSON object mapping formula names to values - EOS - next - end - - formula_names = formula_names.keys if formula_names.is_a? Hash - - invalid_formulae = [] - formula_names.each do |name| - invalid_formulae << name if Formula[name].tap != @name - rescue FormulaUnavailableError - invalid_formulae << name - end - - next if invalid_formulae.empty? - - problem <<~EOS - #{list_directory}/#{list_name}.json references - formulae that are not found in the #{@name} tap. - Invalid formulae: #{invalid_formulae.join(", ")} - EOS - end - end + check_formula_list_directory "audit_exceptions", @tap_audit_exceptions + check_formula_list "pypi_formula_mappings", @tap_pypi_formula_mappings end sig { params(message: String).void } def problem(message) @problems << ({ message: message, location: nil }) end + + private + + sig { params(list_file: String, list: T.untyped).void } + def check_formula_list(list_file, list) + unless [Hash, Array].include? list.class + problem <<~EOS + #{list_file}.json should contain a JSON array + of formula names or a JSON object mapping formula names to values + EOS + return + end + + invalid_formulae = [] + list.each do |name, _| + invalid_formulae << name if Formula[name].tap != @name + rescue FormulaUnavailableError + invalid_formulae << name + end + + return if invalid_formulae.empty? + + problem <<~EOS + #{list_file}.json references + formulae that are not found in the #{@name} tap. + Invalid formulae: #{invalid_formulae.join(", ")} + EOS + end + + sig { params(directory_name: String, lists: Hash).void } + def check_formula_list_directory(directory_name, lists) + lists.each do |list_name, list| + check_formula_list "#{directory_name}/#{list_name}", list + end + end end end diff --git a/Library/Homebrew/utils/pypi.rb b/Library/Homebrew/utils/pypi.rb index 1822951775..4c15a03140 100644 --- a/Library/Homebrew/utils/pypi.rb +++ b/Library/Homebrew/utils/pypi.rb @@ -54,7 +54,7 @@ module PyPI def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil, print_only: false, silent: false, ignore_non_pypi_packages: false) - auto_update_list = formula.tap.formula_lists[:pypi_automatic_resource_update_list] + auto_update_list = formula.tap.pypi_formula_mappings if auto_update_list.present? && auto_update_list.key?(formula.full_name) && package_name.blank? && extra_packages.blank? && exclude_packages.blank? From b2e25d12aa00ff3c78c23087dc265f29c72c35b1 Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Sun, 22 Nov 2020 15:23:43 -0500 Subject: [PATCH 37/39] utils/pypi: refactor package handling --- Library/Homebrew/test/utils/pypi_spec.rb | 171 ++++++++++++++++ Library/Homebrew/utils/pypi.rb | 240 +++++++++++++++-------- 2 files changed, 334 insertions(+), 77 deletions(-) create mode 100644 Library/Homebrew/test/utils/pypi_spec.rb diff --git a/Library/Homebrew/test/utils/pypi_spec.rb b/Library/Homebrew/test/utils/pypi_spec.rb new file mode 100644 index 0000000000..021a2215c8 --- /dev/null +++ b/Library/Homebrew/test/utils/pypi_spec.rb @@ -0,0 +1,171 @@ +# typed: false +# frozen_string_literal: true + +require "utils/pypi" + +describe PyPI do + let(:package_url) do + "https://files.pythonhosted.org/packages/b0/3f/2e1dad67eb172b6443b5eb37eb885a054a55cfd733393071499514140282/"\ + "snakemake-5.29.0.tar.gz" + end + let(:old_package_url) do + "https://files.pythonhosted.org/packages/6f/c4/da52bfdd6168ea46a0fe2b7c983b6c34c377a8733ec177cc00b197a96a9f/"\ + "snakemake-5.28.0.tar.gz" + end + + describe PyPI::Package do + let(:package_checksum) { "47417307d08ecb0707b3b29effc933bd63d8c8e3ab15509c62b685b7614c6568" } + let(:old_package_checksum) { "2367ce91baf7f8fa7738d33aff9670ffdf5410bbac49aeb209f73b45a3425046" } + + let(:package) { described_class.new("snakemake") } + let(:package_with_version) { described_class.new("snakemake==5.28.0") } + let(:package_with_different_version) { described_class.new("snakemake==5.29.0") } + let(:package_with_extra) { described_class.new("snakemake[foo]") } + let(:package_with_extra_and_version) { described_class.new("snakemake[foo]==5.28.0") } + let(:package_from_url) { described_class.new(package_url, is_url: true) } + let(:other_package) { described_class.new("virtualenv==20.2.0") } + + describe "initialize" do + it "initializes name" do + expect(described_class.new("foo").name).to eq "foo" + end + + it "initializes name with extra" do + expect(described_class.new("foo[bar]").name).to eq "foo" + end + + it "initializes extra" do + expect(described_class.new("foo[bar]").extras).to eq ["bar"] + end + + it "initializes multiple extras" do + expect(described_class.new("foo[bar,baz]").extras).to eq ["bar", "baz"] + end + + it "initializes name with version" do + expect(described_class.new("foo==1.2.3").name).to eq "foo" + end + + it "initializes version" do + expect(described_class.new("foo==1.2.3").version).to eq "1.2.3" + end + + it "initializes extra with version" do + expect(described_class.new("foo[bar]==1.2.3").extras).to eq ["bar"] + end + + it "initializes multiple extras with version" do + expect(described_class.new("foo[bar,baz]==1.2.3").extras).to eq ["bar", "baz"] + end + + it "initializes version with extra" do + expect(described_class.new("foo[bar]==1.2.3").version).to eq "1.2.3" + end + + it "initializes version with multiple extras" do + expect(described_class.new("foo[bar,baz]==1.2.3").version).to eq "1.2.3" + end + + it "initializes name from url" do + expect(described_class.new(package_url, is_url: true).name).to eq "snakemake" + end + + it "initializes version from url" do + expect(described_class.new(package_url, is_url: true).version).to eq "5.29.0" + end + end + + describe ".pypi_info", :needs_network do + it "gets pypi info from a package name" do + expect(package.pypi_info.first).to eq "snakemake" + end + + it "gets pypi info from a package name and specified version" do + expect(package.pypi_info(version: "5.29.0")).to eq ["snakemake", package_url, package_checksum, "5.29.0"] + end + + it "gets pypi info from a package name with extra" do + expect(package_with_extra.pypi_info.first).to eq "snakemake" + end + + it "gets pypi info from a package name and version" do + expect(package_with_version.pypi_info).to eq ["snakemake", old_package_url, old_package_checksum, "5.28.0"] + end + + it "gets pypi info from a package name with overriden version" do + expected_result = ["snakemake", package_url, package_checksum, "5.29.0"] + expect(package_with_version.pypi_info(version: "5.29.0")).to eq expected_result + end + + it "gets pypi info from a package name, extras, and version" do + expected_result = ["snakemake", old_package_url, old_package_checksum, "5.28.0"] + expect(package_with_extra_and_version.pypi_info).to eq expected_result + end + + it "gets pypi info from a url" do + expect(package_from_url.pypi_info).to eq ["snakemake", package_url, package_checksum, "5.29.0"] + end + + it "gets pypi info from a url with overriden version" do + expected_result = ["snakemake", old_package_url, old_package_checksum, "5.28.0"] + expect(package_from_url.pypi_info(version: "5.28.0")).to eq expected_result + end + end + + describe ".to_s" do + it "returns string representation of package name" do + expect(package.to_s).to eq "snakemake" + end + + it "returns string representation of package with version" do + expect(package_with_version.to_s).to eq "snakemake==5.28.0" + end + + it "returns string representation of package with extra" do + expect(package_with_extra.to_s).to eq "snakemake[foo]" + end + + it "returns string representation of package with extra and version" do + expect(package_with_extra_and_version.to_s).to eq "snakemake[foo]==5.28.0" + end + + it "returns string representation of package from url" do + expect(package_from_url.to_s).to eq "snakemake==5.29.0" + end + end + + describe ".same_package?" do + it "returns false for different packages" do + expect(package.same_package?(other_package)).to eq false + end + + it "returns true for the same package" do + expect(package.same_package?(package_with_version)).to eq true + end + + it "returns true for the same package with different versions" do + expect(package_with_version.same_package?(package_with_different_version)).to eq true + end + end + + describe "<=>" do + it "returns -1" do + expect(package <=> other_package).to eq((-1)) + end + + it "returns 0" do + expect(package <=> package_with_version).to eq 0 + end + + it "returns 1" do + expect(other_package <=> package_with_extra_and_version).to eq 1 + end + end + end + + describe "update_pypi_url", :needs_network do + it "updates url to new version" do + expect(described_class.update_pypi_url(old_package_url, "5.29.0")).to eq package_url + end + end +end diff --git a/Library/Homebrew/utils/pypi.rb b/Library/Homebrew/utils/pypi.rb index 4c15a03140..d69291b069 100644 --- a/Library/Homebrew/utils/pypi.rb +++ b/Library/Homebrew/utils/pypi.rb @@ -5,6 +5,8 @@ # # @api private module PyPI + extend T::Sig + module_function PYTHONHOSTED_URL_PREFIX = "https://files.pythonhosted.org/packages/" @@ -12,45 +14,119 @@ module PyPI @pipgrip_installed = nil - def url_to_pypi_package_name(url) - return unless url.start_with? PYTHONHOSTED_URL_PREFIX + # PyPI Package + # + # @api private + class Package + extend T::Sig - File.basename(url).match(/^(.+)-[a-z\d.]+$/)[1] + attr_accessor :name + attr_accessor :extras + attr_accessor :version + + sig { params(package_string: String, is_url: T::Boolean).void } + def initialize(package_string, is_url: false) + @pypi_info = nil + + if is_url + unless package_string.start_with?(PYTHONHOSTED_URL_PREFIX) && + match = File.basename(package_string).match(/^(.+)-([a-z\d.]+?)(?:.tar.gz|.zip)$/) + raise ArgumentError, "package should be a valid PyPI url" + end + + @name = match[1] + @version = match[2] + return + end + + @name = package_string + @name, @version = @name.split("==") if @name.include? "==" + + return unless match = @name.match(/^(.*?)\[(.+)\]$/) + + @name = match[1] + @extras = match[2].split "," + end + + # Get name, URL, SHA-256 checksum, and latest version for a given PyPI package. + sig { params(version: T.nilable(T.any(String, Version))).returns(T.nilable(T::Array[String])) } + def pypi_info(version: nil) + return @pypi_info if @pypi_info.present? && version.blank? + + version ||= @version + metadata_url = if version.present? + "https://pypi.org/pypi/#{@name}/#{version}/json" + else + "https://pypi.org/pypi/#{@name}/json" + end + out, _, status = curl_output metadata_url, "--location" + + return unless status.success? + + begin + json = JSON.parse out + rescue JSON::ParserError + return + end + + sdist = json["urls"].find { |url| url["packagetype"] == "sdist" } + return json["info"]["name"] if sdist.nil? + + @pypi_info = [json["info"]["name"], sdist["url"], sdist["digests"]["sha256"], json["info"]["version"]] + end + + sig { returns(T::Boolean) } + def valid_pypi_package? + info = pypi_info + info.present? && info.is_a?(Array) + end + + sig { returns(String) } + def to_s + out = @name + out += "[#{@extras.join(",")}]" if @extras.present? + out += "==#{@version}" if @version.present? + out + end + + sig { params(other: Package).returns(T::Boolean) } + def same_package?(other) + @name.tr("_", "-") == other.name.tr("_", "-") + end + + # Compare only names so we can use .include? on a Package array + sig { params(other: Package).returns(T::Boolean) } + def ==(other) + same_package?(other) + end + + sig { params(other: Package).returns(T.nilable(Integer)) } + def <=>(other) + @name <=> other.name + end end + sig { params(url: String, version: T.any(String, Version)).returns(T.nilable(String)) } def update_pypi_url(url, version) - package = url_to_pypi_package_name url - return if package.nil? + package = Package.new url, is_url: true - _, url = get_pypi_info(package, version) + _, url = package.pypi_info(version: version) url end - # Get name, URL, SHA-256 checksum, and latest version for a given PyPI package. - def get_pypi_info(package, version = nil) - package = package.split("[").first - metadata_url = if version.present? - "https://pypi.org/pypi/#{package}/#{version}/json" - else - "https://pypi.org/pypi/#{package}/json" - end - out, _, status = curl_output metadata_url, "--location" - - return unless status.success? - - begin - json = JSON.parse out - rescue JSON::ParserError - return - end - - sdist = json["urls"].find { |url| url["packagetype"] == "sdist" } - return json["info"]["name"] if sdist.nil? - - [json["info"]["name"], sdist["url"], sdist["digests"]["sha256"], json["info"]["version"]] - end - # Return true if resources were checked (even if no change). + sig do + params( + formula: Formula, + version: T.nilable(String), + package_name: T.nilable(String), + extra_packages: T.nilable(T::Array[String]), + exclude_packages: T.nilable(T::Array[String]), + print_only: T::Boolean, + silent: T::Boolean, + ignore_non_pypi_packages: T::Boolean, + ).returns(T.nilable(T::Boolean)) + end def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil, print_only: false, silent: false, ignore_non_pypi_packages: false) @@ -73,12 +149,17 @@ module PyPI end end - version ||= formula.version if package_name.blank? - package_name ||= url_to_pypi_package_name formula.stable.url - extra_packages ||= [] - exclude_packages ||= [] + main_package = if package_name.present? + Package.new(package_name) + else + begin + Package.new(formula.stable.url, is_url: true) + rescue ArgumentError + nil + end + end - if package_name.blank? + if main_package.blank? return if ignore_non_pypi_packages odie <<~EOS @@ -87,76 +168,81 @@ module PyPI EOS end - input_package_names = { package_name => version } - extra_packages.each do |extra| - extra_name, extra_version = extra.split "==" + unless main_package.valid_pypi_package? + return if ignore_non_pypi_packages - if input_package_names.key?(extra_name) && input_package_names[extra_name] != extra_version - odie "Conflicting versions specified for the `#{extra_name}` package: "\ - "#{input_package_names[extra_name]}, #{extra_version}" + odie "\"#{main_package}\" is not available on PyPI." + end + + main_package.version = version if version.present? + + extra_packages = (extra_packages || []).map { |p| Package.new p } + exclude_packages = (exclude_packages || []).map { |p| Package.new p } + + input_packages = [main_package] + extra_packages.each do |extra_package| + if !extra_package.valid_pypi_package? && !ignore_non_pypi_packages + odie "\"#{extra_package}\" is not available on PyPI." end - input_package_names[extra_name] = extra_version + input_packages.each do |existing_package| + if existing_package.same_package?(extra_package) && existing_package.version != extra_package.version + odie "Conflicting versions specified for the `#{extra_package.name}` package: "\ + "#{existing_package.version}, #{extra_package.version}" + end + end + + input_packages << extra_package unless input_packages.include? extra_package end - input_package_names.each do |name, package_version| - name = name.split("[").first - next if get_pypi_info(name, package_version).present? - - version_string = " at version #{package_version}" if package_version.present? - odie "\"#{name}\"#{version_string} is not available on PyPI." unless ignore_non_pypi_packages - end - - non_pypi_resources = formula.resources.reject do |resource| - resource.url.start_with? PYTHONHOSTED_URL_PREFIX - end - - if non_pypi_resources.present? && !print_only - odie "\"#{formula.name}\" contains non-PyPI resources. Please update the resources manually." + formula.resources.each do |resource| + if !print_only && !resource.url.start_with?(PYTHONHOSTED_URL_PREFIX) + odie "\"#{formula.name}\" contains non-PyPI resources. Please update the resources manually." + end end @pipgrip_installed ||= Formula["pipgrip"].any_version_installed? odie '"pipgrip" must be installed (`brew install pipgrip`)' unless @pipgrip_installed - found_packages = {} - input_package_names.each do |name, package_version| - pypi_package_string = if package_version.present? - "#{name}==#{package_version}" - else - name - end - - ohai "Retrieving PyPI dependencies for \"#{pypi_package_string}\"..." if !print_only && !silent - pipgrip_output = Utils.popen_read Formula["pipgrip"].bin/"pipgrip", "--json", "--no-cache-dir", - pypi_package_string + found_packages = [] + input_packages.each do |package| + ohai "Retrieving PyPI dependencies for \"#{package}\"..." if !print_only && !silent + pipgrip_output = Utils.popen_read Formula["pipgrip"].bin/"pipgrip", "--json", "--no-cache-dir", package.to_s unless $CHILD_STATUS.success? odie <<~EOS - Unable to determine dependencies for \"#{name}\" because of a failure when running - `pipgrip --json --no-cache-dir #{pypi_package_string}`. + Unable to determine dependencies for \"#{package}\" because of a failure when running + `pipgrip --json --no-cache-dir #{package}`. Please update the resources for \"#{formula.name}\" manually. EOS end - found_packages.merge!(JSON.parse(pipgrip_output).to_h) do |conflicting_package, old_version, new_version| - next old_version if old_version == new_version + JSON.parse(pipgrip_output).to_h.each do |new_name, new_version| + new_package = Package.new("#{new_name}==#{new_version}") - odie "Conflicting versions found for the `#{conflicting_package}` resource: #{old_version}, #{new_version}" + found_packages.each do |existing_package| + if existing_package.same_package?(new_package) && existing_package.version != new_package.version + odie "Conflicting versions found for the `#{new_package.name}` resource: "\ + "#{existing_package.version}, #{new_package.version}" + end + end + + found_packages << new_package unless found_packages.include? new_package end end # Remove extra packages that may be included in pipgrip output - exclude_list = %W[#{package_name.split("[").first.downcase} argparse pip setuptools wheel wsgiref] + exclude_list = %W[#{main_package.name} argparse pip setuptools wheel wsgiref].map { |p| Package.new p } found_packages.delete_if { |package| exclude_list.include? package } new_resource_blocks = "" - found_packages.sort.each do |package, package_version| + found_packages.sort.each do |package| if exclude_packages.include? package - ohai "Excluding \"#{package}==#{package_version}\"" if !print_only && !silent + ohai "Excluding \"#{package}\"" if !print_only && !silent next end - ohai "Getting PyPI info for \"#{package}==#{package_version}\"" if !print_only && !silent - name, url, checksum = get_pypi_info package, package_version + ohai "Getting PyPI info for \"#{package}\"" if !print_only && !silent + name, url, checksum = package.pypi_info # Fail if unable to find name, url or checksum for any resource if name.blank? odie "Unable to resolve some dependencies. Please update the resources for \"#{formula.name}\" manually." From b9fc7e100b2bfeb9ed90028c0dd5f4635c943934 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Tue, 24 Nov 2020 21:58:40 +0100 Subject: [PATCH 38/39] Add more BOM debug information. --- Library/Homebrew/unpack_strategy/dmg.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/unpack_strategy/dmg.rb b/Library/Homebrew/unpack_strategy/dmg.rb index 970811bd5c..b8395ddef5 100644 --- a/Library/Homebrew/unpack_strategy/dmg.rb +++ b/Library/Homebrew/unpack_strategy/dmg.rb @@ -106,9 +106,18 @@ module UnpackStrategy args: ["--bom", bomfile.path, "--", path, unpack_dir], verbose: verbose - odebug "BOM contents:", bom if result.stderr.include?("contains no files, nothing copied") - odebug "Directory contents:", Pathname.glob(path/"**/*", File::FNM_DOTMATCH).map(&:to_s).join("\n") + all_paths_find = system_command("find", args: [".", "-print0"], chdir: path, print_stderr: false) + .stdout + .split("\0") + + all_paths_ruby = Pathname.glob(path/"**/*", File::FNM_DOTMATCH) + .map { |p| p.relative_path_from(path).to_s } + + odebug "BOM contents:", bom + odebug "BOM contents (retry):", path.bom + odebug "Directory contents (find):", all_paths_find.join("\n") + odebug "Directory contents (Ruby):", all_paths_ruby.join("\n") end FileUtils.chmod "u+w", Pathname.glob(unpack_dir/"**/*", File::FNM_DOTMATCH).reject(&:symlink?) From 737d9b698b42e9fb9020087a92b76ed95f14f7ef Mon Sep 17 00:00:00 2001 From: Rylan Polster Date: Tue, 24 Nov 2020 16:52:29 -0500 Subject: [PATCH 39/39] fix update-python-resources for formulae not in a tap --- Library/Homebrew/utils/pypi.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/utils/pypi.rb b/Library/Homebrew/utils/pypi.rb index d69291b069..d1cffdfd36 100644 --- a/Library/Homebrew/utils/pypi.rb +++ b/Library/Homebrew/utils/pypi.rb @@ -130,7 +130,7 @@ module PyPI def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil, print_only: false, silent: false, ignore_non_pypi_packages: false) - auto_update_list = formula.tap.pypi_formula_mappings + auto_update_list = formula.tap&.pypi_formula_mappings if auto_update_list.present? && auto_update_list.key?(formula.full_name) && package_name.blank? && extra_packages.blank? && exclude_packages.blank?