mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Add brew bundle --upgrade-formulae
This flag allows you to specify formulae to upgrade, even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set. This is useful for upgrading specific formulae without upgrading all formulae. While we're here, let's add Sorbet signatures to the `Bundle` module because I needed to add a new method there anyway.
This commit is contained in:
parent
e42c792fe3
commit
89d0309b9c
@ -1,4 +1,4 @@
|
|||||||
# typed: true # rubocop:todo Sorbet/StrictSigil
|
# typed: strict
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "English"
|
require "English"
|
||||||
@ -6,11 +6,22 @@ require "English"
|
|||||||
module Homebrew
|
module Homebrew
|
||||||
module Bundle
|
module Bundle
|
||||||
class << self
|
class << self
|
||||||
|
sig { params(args_upgrade_formula: T.nilable(String)).void }
|
||||||
|
def upgrade_formulae=(args_upgrade_formula)
|
||||||
|
@upgrade_formulae = args_upgrade_formula.to_s.split(",")
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Array[String]) }
|
||||||
|
def upgrade_formulae
|
||||||
|
@upgrade_formulae || []
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(cmd: T.any(String, Pathname), args: T.anything, verbose: T::Boolean).returns(T::Boolean) }
|
||||||
def system(cmd, *args, verbose: false)
|
def system(cmd, *args, verbose: false)
|
||||||
return super cmd, *args if verbose
|
return super cmd, *args if verbose
|
||||||
|
|
||||||
logs = []
|
logs = []
|
||||||
success = T.let(nil, T.nilable(T::Boolean))
|
success = T.let(false, T::Boolean)
|
||||||
IO.popen([cmd, *args], err: [:child, :out]) do |pipe|
|
IO.popen([cmd, *args], err: [:child, :out]) do |pipe|
|
||||||
while (buf = pipe.gets)
|
while (buf = pipe.gets)
|
||||||
logs << buf
|
logs << buf
|
||||||
@ -23,18 +34,22 @@ module Homebrew
|
|||||||
success
|
success
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { params(args: T.anything, verbose: T::Boolean).returns(T::Boolean) }
|
||||||
def brew(*args, verbose: false)
|
def brew(*args, verbose: false)
|
||||||
system(HOMEBREW_BREW_FILE, *args, verbose:)
|
system(HOMEBREW_BREW_FILE, *args, verbose:)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
def mas_installed?
|
def mas_installed?
|
||||||
@mas_installed ||= which_formula("mas")
|
@mas_installed ||= which_formula("mas")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
def vscode_installed?
|
def vscode_installed?
|
||||||
@vscode_installed ||= which_vscode.present?
|
@vscode_installed ||= which_vscode.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(Pathname)) }
|
||||||
def which_vscode
|
def which_vscode
|
||||||
@which_vscode ||= which("code", ORIGINAL_PATHS)
|
@which_vscode ||= which("code", ORIGINAL_PATHS)
|
||||||
@which_vscode ||= which("codium", ORIGINAL_PATHS)
|
@which_vscode ||= which("codium", ORIGINAL_PATHS)
|
||||||
@ -42,22 +57,26 @@ module Homebrew
|
|||||||
@which_vscode ||= which("code-insiders", ORIGINAL_PATHS)
|
@which_vscode ||= which("code-insiders", ORIGINAL_PATHS)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
def whalebrew_installed?
|
def whalebrew_installed?
|
||||||
@whalebrew_installed ||= which_formula("whalebrew")
|
@whalebrew_installed ||= which_formula("whalebrew")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
def cask_installed?
|
def cask_installed?
|
||||||
@cask_installed ||= File.directory?("#{HOMEBREW_PREFIX}/Caskroom") &&
|
@cask_installed ||= File.directory?("#{HOMEBREW_PREFIX}/Caskroom") &&
|
||||||
(File.directory?("#{HOMEBREW_LIBRARY}/Taps/homebrew/homebrew-cask") ||
|
(File.directory?("#{HOMEBREW_LIBRARY}/Taps/homebrew/homebrew-cask") ||
|
||||||
!Homebrew::EnvConfig.no_install_from_api?)
|
!Homebrew::EnvConfig.no_install_from_api?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { params(name: String).returns(T::Boolean) }
|
||||||
def which_formula(name)
|
def which_formula(name)
|
||||||
formula = Formulary.factory(name)
|
formula = Formulary.factory(name)
|
||||||
ENV["PATH"] = "#{formula.opt_bin}:#{ENV.fetch("PATH", nil)}" if formula.any_version_installed?
|
ENV["PATH"] = "#{formula.opt_bin}:#{ENV.fetch("PATH", nil)}" if formula.any_version_installed?
|
||||||
which(name).present?
|
which(name).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { params(block: T.proc.returns(T.anything)).returns(T.untyped) }
|
||||||
def exchange_uid_if_needed!(&block)
|
def exchange_uid_if_needed!(&block)
|
||||||
euid = Process.euid
|
euid = Process.euid
|
||||||
uid = Process.uid
|
uid = Process.uid
|
||||||
@ -83,6 +102,7 @@ module Homebrew
|
|||||||
return_value
|
return_value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { returns(T::Hash[String, String]) }
|
||||||
def formula_versions_from_env
|
def formula_versions_from_env
|
||||||
@formula_versions_from_env ||= begin
|
@formula_versions_from_env ||= begin
|
||||||
formula_versions = {}
|
formula_versions = {}
|
||||||
@ -106,11 +126,13 @@ module Homebrew
|
|||||||
|
|
||||||
sig { void }
|
sig { void }
|
||||||
def reset!
|
def reset!
|
||||||
@mas_installed = nil
|
@mas_installed = T.let(nil, T.nilable(T::Boolean))
|
||||||
@vscode_installed = nil
|
@vscode_installed = T.let(nil, T.nilable(T::Boolean))
|
||||||
@whalebrew_installed = nil
|
@which_vscode = T.let(nil, T.nilable(String))
|
||||||
@cask_installed = nil
|
@whalebrew_installed = T.let(nil, T.nilable(T::Boolean))
|
||||||
@formula_versions_from_env = nil
|
@cask_installed = T.let(nil, T.nilable(T::Boolean))
|
||||||
|
@formula_versions_from_env = T.let(nil, T.nilable(T::Hash[String, String]))
|
||||||
|
@upgrade_formulae = T.let(nil, T.nilable(T::Array[String]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -32,7 +32,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def preinstall(no_upgrade: false, verbose: false)
|
def preinstall(no_upgrade: false, verbose: false)
|
||||||
if installed? && (no_upgrade || !upgradable?)
|
if installed? && (self.class.no_upgrade_with_args?(no_upgrade, @name) || !upgradable?)
|
||||||
puts "Skipping install of #{@name} formula. It is already installed." if verbose
|
puts "Skipping install of #{@name} formula. It is already installed." if verbose
|
||||||
@changed = nil
|
@changed = nil
|
||||||
return false
|
return false
|
||||||
@ -166,11 +166,15 @@ module Homebrew
|
|||||||
|
|
||||||
def self.formula_installed_and_up_to_date?(formula, no_upgrade: false)
|
def self.formula_installed_and_up_to_date?(formula, no_upgrade: false)
|
||||||
return false unless formula_installed?(formula)
|
return false unless formula_installed?(formula)
|
||||||
return true if no_upgrade
|
return true if no_upgrade_with_args?(no_upgrade, formula)
|
||||||
|
|
||||||
!formula_upgradable?(formula)
|
!formula_upgradable?(formula)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.no_upgrade_with_args?(no_upgrade, formula_name)
|
||||||
|
no_upgrade && Bundle.upgrade_formulae.exclude?(formula_name)
|
||||||
|
end
|
||||||
|
|
||||||
def self.formula_in_array?(formula, array)
|
def self.formula_in_array?(formula, array)
|
||||||
return true if array.include?(formula)
|
return true if array.include?(formula)
|
||||||
return true if array.include?(formula.split("/").last)
|
return true if array.include?(formula.split("/").last)
|
||||||
|
@ -18,7 +18,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def failure_reason(name, no_upgrade:)
|
def failure_reason(name, no_upgrade:)
|
||||||
reason = if no_upgrade
|
reason = if no_upgrade && Bundle.upgrade_formulae.exclude?(name)
|
||||||
"needs to be installed."
|
"needs to be installed."
|
||||||
else
|
else
|
||||||
"needs to be installed or updated."
|
"needs to be installed or updated."
|
||||||
|
@ -48,7 +48,7 @@ module Homebrew
|
|||||||
|
|
||||||
Bundle.exchange_uid_if_needed! do
|
Bundle.exchange_uid_if_needed! do
|
||||||
vscode_extensions.each do |extension|
|
vscode_extensions.each do |extension|
|
||||||
Kernel.system(Bundle.which_vscode, "--uninstall-extension", extension)
|
Kernel.system(T.must(Bundle.which_vscode).to_s, "--uninstall-extension", extension)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ module Homebrew
|
|||||||
puts "Installing #{name} VSCode extension. It is not currently installed." if verbose
|
puts "Installing #{name} VSCode extension. It is not currently installed." if verbose
|
||||||
|
|
||||||
return false unless Bundle.exchange_uid_if_needed! do
|
return false unless Bundle.exchange_uid_if_needed! do
|
||||||
Bundle.system(Bundle.which_vscode, "--install-extension", name, verbose:)
|
Bundle.system(T.must(Bundle.which_vscode), "--install-extension", name, verbose:)
|
||||||
end
|
end
|
||||||
|
|
||||||
installed_extensions << name
|
installed_extensions << name
|
||||||
|
@ -80,7 +80,10 @@ module Homebrew
|
|||||||
"This is enabled by default if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set."
|
"This is enabled by default if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set."
|
||||||
switch "--upgrade",
|
switch "--upgrade",
|
||||||
description: "`install` runs `brew upgrade` on outdated dependencies, " \
|
description: "`install` runs `brew upgrade` on outdated dependencies, " \
|
||||||
"even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set. "
|
"even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set."
|
||||||
|
flag "--upgrade-formulae=", "--upgrade-formula=",
|
||||||
|
description: "`install` runs `brew upgrade` on any of these comma-separated formulae, " \
|
||||||
|
"even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set."
|
||||||
switch "--install",
|
switch "--install",
|
||||||
description: "Run `install` before continuing to other operations e.g. `exec`."
|
description: "Run `install` before continuing to other operations e.g. `exec`."
|
||||||
switch "--services",
|
switch "--services",
|
||||||
@ -150,6 +153,7 @@ module Homebrew
|
|||||||
verbose = args.verbose?
|
verbose = args.verbose?
|
||||||
force = args.force?
|
force = args.force?
|
||||||
zap = args.zap?
|
zap = args.zap?
|
||||||
|
Homebrew::Bundle.upgrade_formulae = args.upgrade_formulae
|
||||||
|
|
||||||
no_type_args = !args.brews? && !args.casks? && !args.taps? && !args.mas? && !args.whalebrew? && !args.vscode?
|
no_type_args = !args.brews? && !args.casks? && !args.taps? && !args.mas? && !args.whalebrew? && !args.vscode?
|
||||||
|
|
||||||
|
@ -71,6 +71,12 @@ class Homebrew::Cmd::Bundle::Args < Homebrew::CLI::Args
|
|||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def upgrade?; end
|
def upgrade?; end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(String)) }
|
||||||
|
def upgrade_formula; end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(String)) }
|
||||||
|
def upgrade_formulae; end
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def vscode?; end
|
def vscode?; end
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ RSpec.describe Homebrew::Bundle::Commands::Cleanup do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "uninstalls extensions" do
|
it "uninstalls extensions" do
|
||||||
expect(Kernel).to receive(:system).with(Pathname("code"), "--uninstall-extension", "GitHub.codespaces")
|
expect(Kernel).to receive(:system).with("code", "--uninstall-extension", "GitHub.codespaces")
|
||||||
expect(described_class).to receive(:system_output_no_stderr).and_return("")
|
expect(described_class).to receive(:system_output_no_stderr).and_return("")
|
||||||
described_class.run(force: true)
|
described_class.run(force: true)
|
||||||
end
|
end
|
||||||
|
@ -667,6 +667,7 @@ _brew_bundle() {
|
|||||||
--services
|
--services
|
||||||
--tap
|
--tap
|
||||||
--upgrade
|
--upgrade
|
||||||
|
--upgrade-formulae
|
||||||
--verbose
|
--verbose
|
||||||
--vscode
|
--vscode
|
||||||
--whalebrew
|
--whalebrew
|
||||||
|
@ -521,7 +521,8 @@ __fish_brew_complete_arg 'bundle' -l no-vscode -d '`dump` without VSCode (and fo
|
|||||||
__fish_brew_complete_arg 'bundle' -l quiet -d 'Make some output more quiet'
|
__fish_brew_complete_arg 'bundle' -l quiet -d 'Make some output more quiet'
|
||||||
__fish_brew_complete_arg 'bundle' -l services -d 'Temporarily start services while running the `exec` or `sh` command'
|
__fish_brew_complete_arg 'bundle' -l services -d 'Temporarily start services while running the `exec` or `sh` command'
|
||||||
__fish_brew_complete_arg 'bundle' -l tap -d '`list` or `dump` Homebrew tap dependencies'
|
__fish_brew_complete_arg 'bundle' -l tap -d '`list` or `dump` Homebrew tap dependencies'
|
||||||
__fish_brew_complete_arg 'bundle' -l upgrade -d '`install` runs `brew upgrade` on outdated dependencies, even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set. '
|
__fish_brew_complete_arg 'bundle' -l upgrade -d '`install` runs `brew upgrade` on outdated dependencies, even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set'
|
||||||
|
__fish_brew_complete_arg 'bundle' -l upgrade-formulae -d '`install` runs `brew upgrade` on any of these comma-separated formulae, even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set'
|
||||||
__fish_brew_complete_arg 'bundle' -l verbose -d '`install` prints output from commands as they are run. `check` lists all missing dependencies'
|
__fish_brew_complete_arg 'bundle' -l verbose -d '`install` prints output from commands as they are run. `check` lists all missing dependencies'
|
||||||
__fish_brew_complete_arg 'bundle' -l vscode -d '`list` or `dump` VSCode (and forks/variants) extensions'
|
__fish_brew_complete_arg 'bundle' -l vscode -d '`list` or `dump` VSCode (and forks/variants) extensions'
|
||||||
__fish_brew_complete_arg 'bundle' -l whalebrew -d '`list` or `dump` Whalebrew dependencies'
|
__fish_brew_complete_arg 'bundle' -l whalebrew -d '`list` or `dump` Whalebrew dependencies'
|
||||||
|
@ -664,7 +664,8 @@ _brew_bundle() {
|
|||||||
'--quiet[Make some output more quiet]' \
|
'--quiet[Make some output more quiet]' \
|
||||||
'--services[Temporarily start services while running the `exec` or `sh` command]' \
|
'--services[Temporarily start services while running the `exec` or `sh` command]' \
|
||||||
'--tap[`list` or `dump` Homebrew tap dependencies]' \
|
'--tap[`list` or `dump` Homebrew tap dependencies]' \
|
||||||
'(--install)--upgrade[`install` runs `brew upgrade` on outdated dependencies, even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set. ]' \
|
'(--install)--upgrade[`install` runs `brew upgrade` on outdated dependencies, even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set]' \
|
||||||
|
'--upgrade-formulae[`install` runs `brew upgrade` on any of these comma-separated formulae, even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set]' \
|
||||||
'--verbose[`install` prints output from commands as they are run. `check` lists all missing dependencies]' \
|
'--verbose[`install` prints output from commands as they are run. `check` lists all missing dependencies]' \
|
||||||
'(--no-vscode)--vscode[`list` or `dump` VSCode (and forks/variants) extensions]' \
|
'(--no-vscode)--vscode[`list` or `dump` VSCode (and forks/variants) extensions]' \
|
||||||
'--whalebrew[`list` or `dump` Whalebrew dependencies]' \
|
'--whalebrew[`list` or `dump` Whalebrew dependencies]' \
|
||||||
|
@ -247,6 +247,11 @@ flags which will help with finding keg-only dependencies like `openssl`,
|
|||||||
: `install` runs `brew upgrade` on outdated dependencies, even if
|
: `install` runs `brew upgrade` on outdated dependencies, even if
|
||||||
`$HOMEBREW_BUNDLE_NO_UPGRADE` is set.
|
`$HOMEBREW_BUNDLE_NO_UPGRADE` is set.
|
||||||
|
|
||||||
|
`--upgrade-formulae`
|
||||||
|
|
||||||
|
: `install` runs `brew upgrade` on any of these comma-separated formulae, even
|
||||||
|
if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set.
|
||||||
|
|
||||||
`--install`
|
`--install`
|
||||||
|
|
||||||
: Run `install` before continuing to other operations e.g. `exec`.
|
: Run `install` before continuing to other operations e.g. `exec`.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" generated by kramdown
|
.\" generated by kramdown
|
||||||
.TH "BREW" "1" "March 2025" "Homebrew"
|
.TH "BREW" "1" "April 2025" "Homebrew"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
brew \- The Missing Package Manager for macOS (or Linux)
|
brew \- The Missing Package Manager for macOS (or Linux)
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
@ -150,6 +150,9 @@ Read from or write to the \fBBrewfile\fP from \fB$HOMEBREW_BUNDLE_FILE_GLOBAL\fP
|
|||||||
\fB\-\-upgrade\fP
|
\fB\-\-upgrade\fP
|
||||||
\fBinstall\fP runs \fBbrew upgrade\fP on outdated dependencies, even if \fB$HOMEBREW_BUNDLE_NO_UPGRADE\fP is set\.
|
\fBinstall\fP runs \fBbrew upgrade\fP on outdated dependencies, even if \fB$HOMEBREW_BUNDLE_NO_UPGRADE\fP is set\.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-upgrade\-formulae\fP
|
||||||
|
\fBinstall\fP runs \fBbrew upgrade\fP on any of these comma\-separated formulae, even if \fB$HOMEBREW_BUNDLE_NO_UPGRADE\fP is set\.
|
||||||
|
.TP
|
||||||
\fB\-\-install\fP
|
\fB\-\-install\fP
|
||||||
Run \fBinstall\fP before continuing to other operations e\.g\. \fBexec\fP\&\.
|
Run \fBinstall\fP before continuing to other operations e\.g\. \fBexec\fP\&\.
|
||||||
.TP
|
.TP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user