Merge pull request #16998 from Homebrew/ported-cmds
Port remaining commands to use AbstractCommand
This commit is contained in:
commit
0b98c50866
@ -1,122 +1,128 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "fetch"
|
||||
require "cli/parser"
|
||||
require "cask/download"
|
||||
|
||||
module Homebrew
|
||||
extend Fetch
|
||||
module Cmd
|
||||
class Cache < AbstractCommand
|
||||
include Fetch
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.__cache_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Display Homebrew's download cache. See also `HOMEBREW_CACHE`.
|
||||
sig { override.returns(String) }
|
||||
def self.command_name = "--cache"
|
||||
|
||||
If <formula> is provided, display the file or directory used to cache <formula>.
|
||||
EOS
|
||||
flag "--os=",
|
||||
description: "Show cache file for the given operating system. " \
|
||||
"(Pass `all` to show cache files for all operating systems.)"
|
||||
flag "--arch=",
|
||||
description: "Show cache file for the given CPU architecture. " \
|
||||
"(Pass `all` to show cache files for all architectures.)"
|
||||
switch "-s", "--build-from-source",
|
||||
description: "Show the cache file used when building from source."
|
||||
switch "--force-bottle",
|
||||
description: "Show the cache file used when pouring a bottle."
|
||||
flag "--bottle-tag=",
|
||||
description: "Show the cache file used when pouring a bottle for the given tag."
|
||||
switch "--HEAD",
|
||||
description: "Show the cache file used when building from HEAD."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Only show cache files for formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Only show cache files for casks."
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Display Homebrew's download cache. See also `HOMEBREW_CACHE`.
|
||||
|
||||
conflicts "--build-from-source", "--force-bottle", "--bottle-tag", "--HEAD", "--cask"
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--os", "--bottle-tag"
|
||||
conflicts "--arch", "--bottle-tag"
|
||||
If <formula> is provided, display the file or directory used to cache <formula>.
|
||||
EOS
|
||||
flag "--os=",
|
||||
description: "Show cache file for the given operating system. " \
|
||||
"(Pass `all` to show cache files for all operating systems.)"
|
||||
flag "--arch=",
|
||||
description: "Show cache file for the given CPU architecture. " \
|
||||
"(Pass `all` to show cache files for all architectures.)"
|
||||
switch "-s", "--build-from-source",
|
||||
description: "Show the cache file used when building from source."
|
||||
switch "--force-bottle",
|
||||
description: "Show the cache file used when pouring a bottle."
|
||||
flag "--bottle-tag=",
|
||||
description: "Show the cache file used when pouring a bottle for the given tag."
|
||||
switch "--HEAD",
|
||||
description: "Show the cache file used when building from HEAD."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Only show cache files for formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Only show cache files for casks."
|
||||
|
||||
named_args [:formula, :cask]
|
||||
end
|
||||
end
|
||||
conflicts "--build-from-source", "--force-bottle", "--bottle-tag", "--HEAD", "--cask"
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--os", "--bottle-tag"
|
||||
conflicts "--arch", "--bottle-tag"
|
||||
|
||||
sig { void }
|
||||
def self.__cache
|
||||
args = __cache_args.parse
|
||||
named_args [:formula, :cask]
|
||||
end
|
||||
|
||||
if args.no_named?
|
||||
puts HOMEBREW_CACHE
|
||||
return
|
||||
end
|
||||
|
||||
formulae_or_casks = args.named.to_formulae_and_casks
|
||||
os_arch_combinations = args.os_arch_combinations
|
||||
|
||||
formulae_or_casks.each do |formula_or_cask|
|
||||
case formula_or_cask
|
||||
when Formula
|
||||
formula = formula_or_cask
|
||||
ref = formula.loaded_from_api? ? formula.full_name : formula.path
|
||||
|
||||
os_arch_combinations.each do |os, arch|
|
||||
SimulateSystem.with(os:, arch:) do
|
||||
formula = Formulary.factory(ref)
|
||||
print_formula_cache(formula, os:, arch:, args:)
|
||||
end
|
||||
sig { override.void }
|
||||
def run
|
||||
if args.no_named?
|
||||
puts HOMEBREW_CACHE
|
||||
return
|
||||
end
|
||||
else
|
||||
cask = formula_or_cask
|
||||
ref = cask.loaded_from_api? ? cask.full_name : cask.sourcefile_path
|
||||
|
||||
os_arch_combinations.each do |os, arch|
|
||||
next if os == :linux
|
||||
formulae_or_casks = args.named.to_formulae_and_casks
|
||||
os_arch_combinations = args.os_arch_combinations
|
||||
|
||||
SimulateSystem.with(os:, arch:) do
|
||||
cask = Cask::CaskLoader.load(ref)
|
||||
print_cask_cache(cask)
|
||||
formulae_or_casks.each do |formula_or_cask|
|
||||
case formula_or_cask
|
||||
when Formula
|
||||
formula = formula_or_cask
|
||||
ref = formula.loaded_from_api? ? formula.full_name : formula.path
|
||||
|
||||
os_arch_combinations.each do |os, arch|
|
||||
SimulateSystem.with(os:, arch:) do
|
||||
formula = Formulary.factory(ref)
|
||||
print_formula_cache(formula, os:, arch:)
|
||||
end
|
||||
end
|
||||
when Cask::Cask
|
||||
cask = formula_or_cask
|
||||
ref = cask.loaded_from_api? ? cask.full_name : cask.sourcefile_path
|
||||
|
||||
os_arch_combinations.each do |os, arch|
|
||||
next if os == :linux
|
||||
|
||||
SimulateSystem.with(os:, arch:) do
|
||||
loaded_cask = Cask::CaskLoader.load(ref)
|
||||
print_cask_cache(loaded_cask)
|
||||
end
|
||||
end
|
||||
else
|
||||
raise "Invalid type: #{formula_or_cask.class}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(formula: Formula, os: Symbol, arch: Symbol, args: CLI::Args).void }
|
||||
def self.print_formula_cache(formula, os:, arch:, args:)
|
||||
if fetch_bottle?(
|
||||
formula,
|
||||
force_bottle: args.force_bottle?,
|
||||
bottle_tag: args.bottle_tag&.to_sym,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
os: args.os&.to_sym,
|
||||
arch: args.arch&.to_sym,
|
||||
)
|
||||
bottle_tag = if (bottle_tag = args.bottle_tag&.to_sym)
|
||||
Utils::Bottles::Tag.from_symbol(bottle_tag)
|
||||
else
|
||||
Utils::Bottles::Tag.new(system: os, arch:)
|
||||
private
|
||||
|
||||
sig { params(formula: Formula, os: Symbol, arch: Symbol).void }
|
||||
def print_formula_cache(formula, os:, arch:)
|
||||
if fetch_bottle?(
|
||||
formula,
|
||||
force_bottle: args.force_bottle?,
|
||||
bottle_tag: args.bottle_tag&.to_sym,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
os: args.os&.to_sym,
|
||||
arch: args.arch&.to_sym,
|
||||
)
|
||||
bottle_tag = if (bottle_tag = args.bottle_tag&.to_sym)
|
||||
Utils::Bottles::Tag.from_symbol(bottle_tag)
|
||||
else
|
||||
Utils::Bottles::Tag.new(system: os, arch:)
|
||||
end
|
||||
|
||||
bottle = formula.bottle_for_tag(bottle_tag)
|
||||
|
||||
if bottle.nil?
|
||||
opoo "Bottle for tag #{bottle_tag.to_sym.inspect} is unavailable."
|
||||
return
|
||||
end
|
||||
|
||||
puts bottle.cached_download
|
||||
elsif args.HEAD?
|
||||
puts T.must(formula.head).cached_download
|
||||
else
|
||||
puts formula.cached_download
|
||||
end
|
||||
end
|
||||
|
||||
bottle = formula.bottle_for_tag(bottle_tag)
|
||||
|
||||
if bottle.nil?
|
||||
opoo "Bottle for tag #{bottle_tag.to_sym.inspect} is unavailable."
|
||||
return
|
||||
sig { params(cask: Cask::Cask).void }
|
||||
def print_cask_cache(cask)
|
||||
puts Cask::Download.new(cask).downloader.cached_location
|
||||
end
|
||||
|
||||
puts bottle.cached_download
|
||||
elsif args.HEAD?
|
||||
puts T.must(formula.head).cached_download
|
||||
else
|
||||
puts formula.cached_download
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(cask: Cask::Cask).void }
|
||||
def self.print_cask_cache(cask)
|
||||
puts Cask::Download.new(cask).downloader.cached_location
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,32 +1,34 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Caskroom < AbstractCommand
|
||||
sig { override.returns(String) }
|
||||
def self.command_name = "--caskroom"
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def __caskroom_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Display Homebrew's Caskroom path.
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Display Homebrew's Caskroom path.
|
||||
|
||||
If <cask> is provided, display the location in the Caskroom where <cask>
|
||||
would be installed, without any sort of versioned directory as the last path.
|
||||
EOS
|
||||
If <cask> is provided, display the location in the Caskroom where <cask>
|
||||
would be installed, without any sort of versioned directory as the last path.
|
||||
EOS
|
||||
|
||||
named_args :cask
|
||||
end
|
||||
end
|
||||
named_args :cask
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def __caskroom
|
||||
args = __caskroom_args.parse
|
||||
|
||||
if args.named.to_casks.blank?
|
||||
puts Cask::Caskroom.path
|
||||
else
|
||||
args.named.to_casks.each do |cask|
|
||||
puts "#{Cask::Caskroom.path}/#{cask.token}"
|
||||
sig { override.void }
|
||||
def run
|
||||
if args.named.to_casks.blank?
|
||||
puts Cask::Caskroom.path
|
||||
else
|
||||
args.named.to_casks.each do |cask|
|
||||
puts "#{Cask::Caskroom.path}/#{cask.token}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,32 +1,34 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Cellar < AbstractCommand
|
||||
sig { override.returns(String) }
|
||||
def self.command_name = "--cellar"
|
||||
|
||||
def __cellar_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Display Homebrew's Cellar path. *Default:* `$(brew --prefix)/Cellar`, or if
|
||||
that directory doesn't exist, `$(brew --repository)/Cellar`.
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Display Homebrew's Cellar path. *Default:* `$(brew --prefix)/Cellar`, or if
|
||||
that directory doesn't exist, `$(brew --repository)/Cellar`.
|
||||
|
||||
If <formula> is provided, display the location in the Cellar where <formula>
|
||||
would be installed, without any sort of versioned directory as the last path.
|
||||
EOS
|
||||
If <formula> is provided, display the location in the Cellar where <formula>
|
||||
would be installed, without any sort of versioned directory as the last path.
|
||||
EOS
|
||||
|
||||
named_args :formula
|
||||
end
|
||||
end
|
||||
named_args :formula
|
||||
end
|
||||
|
||||
def __cellar
|
||||
args = __cellar_args.parse
|
||||
|
||||
if args.no_named?
|
||||
puts HOMEBREW_CELLAR
|
||||
else
|
||||
puts args.named.to_resolved_formulae.map(&:rack)
|
||||
sig { override.void }
|
||||
def run
|
||||
if args.no_named?
|
||||
puts HOMEBREW_CELLAR
|
||||
else
|
||||
puts args.named.to_resolved_formulae.map(&:rack)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,56 +1,56 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "extend/ENV"
|
||||
require "build_environment"
|
||||
require "utils/shell"
|
||||
require "cli/parser"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Env < AbstractCommand
|
||||
sig { override.returns(String) }
|
||||
def self.command_name = "--env"
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def __env_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Summarise Homebrew's build environment as a plain list.
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Summarise Homebrew's build environment as a plain list.
|
||||
|
||||
If the command's output is sent through a pipe and no shell is specified,
|
||||
the list is formatted for export to `bash`(1) unless `--plain` is passed.
|
||||
EOS
|
||||
flag "--shell=",
|
||||
description: "Generate a list of environment variables for the specified shell, " \
|
||||
"or `--shell=auto` to detect the current shell."
|
||||
switch "--plain",
|
||||
description: "Generate plain output even when piped."
|
||||
If the command's output is sent through a pipe and no shell is specified,
|
||||
the list is formatted for export to `bash`(1) unless `--plain` is passed.
|
||||
EOS
|
||||
flag "--shell=",
|
||||
description: "Generate a list of environment variables for the specified shell, " \
|
||||
"or `--shell=auto` to detect the current shell."
|
||||
switch "--plain",
|
||||
description: "Generate plain output even when piped."
|
||||
|
||||
named_args :formula
|
||||
end
|
||||
end
|
||||
named_args :formula
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def __env
|
||||
args = __env_args.parse
|
||||
sig { override.void }
|
||||
def run
|
||||
ENV.activate_extensions!
|
||||
ENV.deps = args.named.to_formulae if superenv?(nil)
|
||||
ENV.setup_build_environment
|
||||
|
||||
ENV.activate_extensions!
|
||||
ENV.deps = args.named.to_formulae if superenv?(nil)
|
||||
ENV.setup_build_environment
|
||||
shell = if args.plain?
|
||||
nil
|
||||
elsif args.shell.nil?
|
||||
:bash unless $stdout.tty?
|
||||
elsif args.shell == "auto"
|
||||
Utils::Shell.parent || Utils::Shell.preferred
|
||||
elsif args.shell
|
||||
Utils::Shell.from_path(T.must(args.shell))
|
||||
end
|
||||
|
||||
shell = if args.plain?
|
||||
nil
|
||||
elsif args.shell.nil?
|
||||
:bash unless $stdout.tty?
|
||||
elsif args.shell == "auto"
|
||||
Utils::Shell.parent || Utils::Shell.preferred
|
||||
elsif args.shell
|
||||
Utils::Shell.from_path(args.shell)
|
||||
end
|
||||
|
||||
if shell.nil?
|
||||
BuildEnvironment.dump ENV.to_h
|
||||
else
|
||||
BuildEnvironment.keys(ENV.to_h).each do |key|
|
||||
puts Utils::Shell.export_value(key, ENV.fetch(key), shell)
|
||||
if shell.nil?
|
||||
BuildEnvironment.dump ENV.to_h
|
||||
else
|
||||
BuildEnvironment.keys(ENV.to_h).each do |key|
|
||||
puts Utils::Shell.export_value(key, ENV.fetch(key), shell)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,106 +1,114 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "fileutils"
|
||||
|
||||
module Homebrew
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.__prefix_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Display Homebrew's install path. *Default:*
|
||||
module Cmd
|
||||
class Prefix < AbstractCommand
|
||||
include FileUtils
|
||||
|
||||
- macOS ARM: `#{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX}`
|
||||
- macOS Intel: `#{HOMEBREW_DEFAULT_PREFIX}`
|
||||
- Linux: `#{HOMEBREW_LINUX_DEFAULT_PREFIX}`
|
||||
UNBREWED_EXCLUDE_FILES = %w[.DS_Store].freeze
|
||||
UNBREWED_EXCLUDE_PATHS = %w[
|
||||
*/.keepme
|
||||
.github/*
|
||||
bin/brew
|
||||
completions/zsh/_brew
|
||||
docs/*
|
||||
lib/gdk-pixbuf-2.0/*
|
||||
lib/gio/*
|
||||
lib/node_modules/*
|
||||
lib/python[23].[0-9]/*
|
||||
lib/python3.[0-9][0-9]/*
|
||||
lib/pypy/*
|
||||
lib/pypy3/*
|
||||
lib/ruby/gems/[12].*
|
||||
lib/ruby/site_ruby/[12].*
|
||||
lib/ruby/vendor_ruby/[12].*
|
||||
manpages/brew.1
|
||||
share/pypy/*
|
||||
share/pypy3/*
|
||||
share/info/dir
|
||||
share/man/whatis
|
||||
share/mime/*
|
||||
texlive/*
|
||||
].freeze
|
||||
|
||||
If <formula> is provided, display the location where <formula> is or would be installed.
|
||||
EOS
|
||||
switch "--unbrewed",
|
||||
description: "List files in Homebrew's prefix not installed by Homebrew."
|
||||
switch "--installed",
|
||||
description: "Outputs nothing and returns a failing status code if <formula> is not installed."
|
||||
conflicts "--unbrewed", "--installed"
|
||||
sig { override.returns(String) }
|
||||
def self.command_name = "--prefix"
|
||||
|
||||
named_args :formula
|
||||
end
|
||||
end
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Display Homebrew's install path. *Default:*
|
||||
|
||||
def self.__prefix
|
||||
args = __prefix_args.parse
|
||||
- macOS ARM: `#{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX}`
|
||||
- macOS Intel: `#{HOMEBREW_DEFAULT_PREFIX}`
|
||||
- Linux: `#{HOMEBREW_LINUX_DEFAULT_PREFIX}`
|
||||
|
||||
raise UsageError, "`--installed` requires a formula argument." if args.installed? && args.no_named?
|
||||
|
||||
if args.unbrewed?
|
||||
raise UsageError, "`--unbrewed` does not take a formula argument." unless args.no_named?
|
||||
|
||||
list_unbrewed
|
||||
elsif args.no_named?
|
||||
puts HOMEBREW_PREFIX
|
||||
else
|
||||
formulae = args.named.to_resolved_formulae
|
||||
prefixes = formulae.filter_map do |f|
|
||||
next nil if args.installed? && !f.opt_prefix.exist?
|
||||
|
||||
# this case will be short-circuited by brew.sh logic for a single formula
|
||||
f.opt_prefix
|
||||
end
|
||||
puts prefixes
|
||||
if args.installed?
|
||||
missing_formulae = formulae.reject(&:optlinked?)
|
||||
.map(&:name)
|
||||
return if missing_formulae.blank?
|
||||
|
||||
raise NotAKegError, <<~EOS
|
||||
The following formulae are not installed:
|
||||
#{missing_formulae.join(" ")}
|
||||
If <formula> is provided, display the location where <formula> is or would be installed.
|
||||
EOS
|
||||
switch "--unbrewed",
|
||||
description: "List files in Homebrew's prefix not installed by Homebrew."
|
||||
switch "--installed",
|
||||
description: "Outputs nothing and returns a failing status code if <formula> is not installed."
|
||||
conflicts "--unbrewed", "--installed"
|
||||
|
||||
named_args :formula
|
||||
end
|
||||
|
||||
sig { override.void }
|
||||
def run
|
||||
raise UsageError, "`--installed` requires a formula argument." if args.installed? && args.no_named?
|
||||
|
||||
if args.unbrewed?
|
||||
raise UsageError, "`--unbrewed` does not take a formula argument." unless args.no_named?
|
||||
|
||||
list_unbrewed
|
||||
elsif args.no_named?
|
||||
puts HOMEBREW_PREFIX
|
||||
else
|
||||
formulae = args.named.to_resolved_formulae
|
||||
prefixes = formulae.filter_map do |f|
|
||||
next nil if args.installed? && !f.opt_prefix.exist?
|
||||
|
||||
# this case will be short-circuited by brew.sh logic for a single formula
|
||||
f.opt_prefix
|
||||
end
|
||||
puts prefixes
|
||||
if args.installed?
|
||||
missing_formulae = formulae.reject(&:optlinked?)
|
||||
.map(&:name)
|
||||
return if missing_formulae.blank?
|
||||
|
||||
raise NotAKegError, <<~EOS
|
||||
The following formulae are not installed:
|
||||
#{missing_formulae.join(" ")}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def list_unbrewed
|
||||
dirs = HOMEBREW_PREFIX.subdirs.map { |dir| dir.basename.to_s }
|
||||
dirs -= %w[Library Cellar Caskroom .git]
|
||||
|
||||
# Exclude cache, logs, and repository, if they are located under the prefix.
|
||||
[HOMEBREW_CACHE, HOMEBREW_LOGS, HOMEBREW_REPOSITORY].each do |dir|
|
||||
dirs.delete dir.relative_path_from(HOMEBREW_PREFIX).to_s
|
||||
end
|
||||
dirs.delete "etc"
|
||||
dirs.delete "var"
|
||||
|
||||
arguments = dirs.sort + %w[-type f (]
|
||||
arguments.concat UNBREWED_EXCLUDE_FILES.flat_map { |f| %W[! -name #{f}] }
|
||||
arguments.concat UNBREWED_EXCLUDE_PATHS.flat_map { |d| %W[! -path #{d}] }
|
||||
arguments.push ")"
|
||||
|
||||
cd(HOMEBREW_PREFIX) { safe_system("find", *arguments) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
UNBREWED_EXCLUDE_FILES = %w[.DS_Store].freeze
|
||||
UNBREWED_EXCLUDE_PATHS = %w[
|
||||
*/.keepme
|
||||
.github/*
|
||||
bin/brew
|
||||
completions/zsh/_brew
|
||||
docs/*
|
||||
lib/gdk-pixbuf-2.0/*
|
||||
lib/gio/*
|
||||
lib/node_modules/*
|
||||
lib/python[23].[0-9]/*
|
||||
lib/python3.[0-9][0-9]/*
|
||||
lib/pypy/*
|
||||
lib/pypy3/*
|
||||
lib/ruby/gems/[12].*
|
||||
lib/ruby/site_ruby/[12].*
|
||||
lib/ruby/vendor_ruby/[12].*
|
||||
manpages/brew.1
|
||||
share/pypy/*
|
||||
share/pypy3/*
|
||||
share/info/dir
|
||||
share/man/whatis
|
||||
share/mime/*
|
||||
texlive/*
|
||||
].freeze
|
||||
|
||||
def self.list_unbrewed
|
||||
dirs = HOMEBREW_PREFIX.subdirs.map { |dir| dir.basename.to_s }
|
||||
dirs -= %w[Library Cellar Caskroom .git]
|
||||
|
||||
# Exclude cache, logs, and repository, if they are located under the prefix.
|
||||
[HOMEBREW_CACHE, HOMEBREW_LOGS, HOMEBREW_REPOSITORY].each do |dir|
|
||||
dirs.delete dir.relative_path_from(HOMEBREW_PREFIX).to_s
|
||||
end
|
||||
dirs.delete "etc"
|
||||
dirs.delete "var"
|
||||
|
||||
arguments = dirs.sort + %w[-type f (]
|
||||
arguments.concat UNBREWED_EXCLUDE_FILES.flat_map { |f| %W[! -name #{f}] }
|
||||
arguments.concat UNBREWED_EXCLUDE_PATHS.flat_map { |d| %W[! -path #{d}] }
|
||||
arguments.push ")"
|
||||
|
||||
cd(HOMEBREW_PREFIX) { safe_system("find", *arguments) }
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,32 +1,32 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Repository < AbstractCommand
|
||||
sig { override.returns(String) }
|
||||
def self.command_name = "--repository"
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def __repository_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Display where Homebrew's Git repository is located.
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Display where Homebrew's Git repository is located.
|
||||
|
||||
If <user>`/`<repo> are provided, display where tap <user>`/`<repo>'s directory is located.
|
||||
EOS
|
||||
If <user>`/`<repo> are provided, display where tap <user>`/`<repo>'s directory is located.
|
||||
EOS
|
||||
|
||||
named_args :tap
|
||||
end
|
||||
end
|
||||
named_args :tap
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def __repository
|
||||
args = __repository_args.parse
|
||||
|
||||
if args.no_named?
|
||||
puts HOMEBREW_REPOSITORY
|
||||
else
|
||||
puts args.named.to_taps.map(&:path)
|
||||
sig { override.void }
|
||||
def run
|
||||
if args.no_named?
|
||||
puts HOMEBREW_REPOSITORY
|
||||
else
|
||||
puts args.named.to_taps.map(&:path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,83 +1,88 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "fileutils"
|
||||
|
||||
module Homebrew
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.log_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Show the `git log` for <formula> or <cask>, or show the log for the Homebrew repository
|
||||
if no formula or cask is provided.
|
||||
EOS
|
||||
switch "-p", "-u", "--patch",
|
||||
description: "Also print patch from commit."
|
||||
switch "--stat",
|
||||
description: "Also print diffstat from commit."
|
||||
switch "--oneline",
|
||||
description: "Print only one line per commit."
|
||||
switch "-1",
|
||||
description: "Print only one commit."
|
||||
flag "-n", "--max-count=",
|
||||
description: "Print only a specified number of commits."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Treat all named arguments as formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Treat all named arguments as casks."
|
||||
module Cmd
|
||||
class Log < AbstractCommand
|
||||
include FileUtils
|
||||
|
||||
conflicts "-1", "--max-count"
|
||||
conflicts "--formula", "--cask"
|
||||
|
||||
named_args [:formula, :cask], max: 1, without_api: true
|
||||
end
|
||||
end
|
||||
|
||||
def self.log
|
||||
args = log_args.parse
|
||||
|
||||
# As this command is simplifying user-run commands then let's just use a
|
||||
# user path, too.
|
||||
ENV["PATH"] = PATH.new(ORIGINAL_PATHS).to_s
|
||||
|
||||
if args.no_named?
|
||||
git_log(HOMEBREW_REPOSITORY, args:)
|
||||
else
|
||||
path = args.named.to_paths.first
|
||||
tap = Tap.from_path(path)
|
||||
git_log path.dirname, path, tap, args:
|
||||
end
|
||||
end
|
||||
|
||||
def self.git_log(cd_dir, path = nil, tap = nil, args:)
|
||||
cd cd_dir do
|
||||
repo = Utils.popen_read("git", "rev-parse", "--show-toplevel").chomp
|
||||
if tap
|
||||
name = tap.to_s
|
||||
git_cd = "$(brew --repo #{tap})"
|
||||
elsif cd_dir == HOMEBREW_REPOSITORY
|
||||
name = "Homebrew/brew"
|
||||
git_cd = "$(brew --repo)"
|
||||
else
|
||||
name, git_cd = cd_dir
|
||||
end
|
||||
|
||||
if File.exist? "#{repo}/.git/shallow"
|
||||
opoo <<~EOS
|
||||
#{name} is a shallow clone so only partial output will be shown.
|
||||
To get a full clone, run:
|
||||
git -C "#{git_cd}" fetch --unshallow
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Show the `git log` for <formula> or <cask>, or show the log for the Homebrew repository
|
||||
if no formula or cask is provided.
|
||||
EOS
|
||||
switch "-p", "-u", "--patch",
|
||||
description: "Also print patch from commit."
|
||||
switch "--stat",
|
||||
description: "Also print diffstat from commit."
|
||||
switch "--oneline",
|
||||
description: "Print only one line per commit."
|
||||
switch "-1",
|
||||
description: "Print only one commit."
|
||||
flag "-n", "--max-count=",
|
||||
description: "Print only a specified number of commits."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Treat all named arguments as formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Treat all named arguments as casks."
|
||||
|
||||
conflicts "-1", "--max-count"
|
||||
conflicts "--formula", "--cask"
|
||||
|
||||
named_args [:formula, :cask], max: 1, without_api: true
|
||||
end
|
||||
|
||||
git_args = []
|
||||
git_args << "--patch" if args.patch?
|
||||
git_args << "--stat" if args.stat?
|
||||
git_args << "--oneline" if args.oneline?
|
||||
git_args << "-1" if args.public_send(:"1?")
|
||||
git_args << "--max-count" << args.max_count if args.max_count
|
||||
git_args += ["--follow", "--", path] if path.present?
|
||||
system "git", "log", *git_args
|
||||
sig { override.void }
|
||||
def run
|
||||
# As this command is simplifying user-run commands then let's just use a
|
||||
# user path, too.
|
||||
ENV["PATH"] = PATH.new(ORIGINAL_PATHS).to_s
|
||||
|
||||
if args.no_named?
|
||||
git_log(HOMEBREW_REPOSITORY, args:)
|
||||
else
|
||||
path = args.named.to_paths.first
|
||||
tap = Tap.from_path(path)
|
||||
git_log T.must(path).dirname, path, tap
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def git_log(cd_dir, path = nil, tap = nil)
|
||||
cd cd_dir do
|
||||
repo = Utils.popen_read("git", "rev-parse", "--show-toplevel").chomp
|
||||
if tap
|
||||
name = tap.to_s
|
||||
git_cd = "$(brew --repo #{tap})"
|
||||
elsif cd_dir == HOMEBREW_REPOSITORY
|
||||
name = "Homebrew/brew"
|
||||
git_cd = "$(brew --repo)"
|
||||
else
|
||||
name, git_cd = cd_dir
|
||||
end
|
||||
|
||||
if File.exist? "#{repo}/.git/shallow"
|
||||
opoo <<~EOS
|
||||
#{name} is a shallow clone so only partial output will be shown.
|
||||
To get a full clone, run:
|
||||
git -C "#{git_cd}" fetch --unshallow
|
||||
EOS
|
||||
end
|
||||
|
||||
git_args = []
|
||||
git_args << "--patch" if args.patch?
|
||||
git_args << "--stat" if args.stat?
|
||||
git_args << "--oneline" if args.oneline?
|
||||
git_args << "-1" if args.public_send(:"1?")
|
||||
git_args << "--max-count" << args.max_count if args.max_count
|
||||
git_args += ["--follow", "--", path] if path.present?
|
||||
system "git", "log", *git_args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,43 +1,43 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "migrator"
|
||||
require "cli/parser"
|
||||
require "cask/migrator"
|
||||
|
||||
module Homebrew
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.migrate_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Migrate renamed packages to new names, where <formula> are old names of
|
||||
packages.
|
||||
EOS
|
||||
switch "-f", "--force",
|
||||
description: "Treat installed <formula> and provided <formula> as if they are from " \
|
||||
"the same taps and migrate them anyway."
|
||||
switch "-n", "--dry-run",
|
||||
description: "Show what would be migrated, but do not actually migrate anything."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Only migrate formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Only migrate casks."
|
||||
module Cmd
|
||||
class Migrate < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Migrate renamed packages to new names, where <formula> are old names of
|
||||
packages.
|
||||
EOS
|
||||
switch "-f", "--force",
|
||||
description: "Treat installed <formula> and provided <formula> as if they are from " \
|
||||
"the same taps and migrate them anyway."
|
||||
switch "-n", "--dry-run",
|
||||
description: "Show what would be migrated, but do not actually migrate anything."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Only migrate formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Only migrate casks."
|
||||
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--formula", "--cask"
|
||||
|
||||
named_args [:installed_formula, :installed_cask], min: 1
|
||||
end
|
||||
end
|
||||
named_args [:installed_formula, :installed_cask], min: 1
|
||||
end
|
||||
|
||||
def self.migrate
|
||||
args = migrate_args.parse
|
||||
|
||||
args.named.to_formulae_and_casks(warn: false).each do |formula_or_cask|
|
||||
case formula_or_cask
|
||||
when Formula
|
||||
Migrator.migrate_if_needed(formula_or_cask, force: args.force?, dry_run: args.dry_run?)
|
||||
when Cask::Cask
|
||||
Cask::Migrator.migrate_if_needed(formula_or_cask, dry_run: args.dry_run?)
|
||||
sig { override.void }
|
||||
def run
|
||||
args.named.to_formulae_and_casks(warn: false).each do |formula_or_cask|
|
||||
case formula_or_cask
|
||||
when Formula
|
||||
Migrator.migrate_if_needed(formula_or_cask, force: args.force?, dry_run: args.dry_run?)
|
||||
when Cask::Cask
|
||||
Cask::Migrator.migrate_if_needed(formula_or_cask, dry_run: args.dry_run?)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,48 +1,46 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "tab"
|
||||
require "diagnostic"
|
||||
require "cli/parser"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Missing < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Check the given <formula> kegs for missing dependencies. If no <formula> are
|
||||
provided, check all kegs. Will exit with a non-zero status if any kegs are found
|
||||
to be missing dependencies.
|
||||
EOS
|
||||
comma_array "--hide",
|
||||
description: "Act as if none of the specified <hidden> are installed. <hidden> should be " \
|
||||
"a comma-separated list of formulae."
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def missing_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Check the given <formula> kegs for missing dependencies. If no <formula> are
|
||||
provided, check all kegs. Will exit with a non-zero status if any kegs are found
|
||||
to be missing dependencies.
|
||||
EOS
|
||||
comma_array "--hide",
|
||||
description: "Act as if none of the specified <hidden> are installed. <hidden> should be " \
|
||||
"a comma-separated list of formulae."
|
||||
named_args :formula
|
||||
end
|
||||
|
||||
named_args :formula
|
||||
end
|
||||
end
|
||||
sig { override.void }
|
||||
def run
|
||||
return unless HOMEBREW_CELLAR.exist?
|
||||
|
||||
def missing
|
||||
args = missing_args.parse
|
||||
ff = if args.no_named?
|
||||
Formula.installed.sort
|
||||
else
|
||||
args.named.to_resolved_formulae.sort
|
||||
end
|
||||
|
||||
return unless HOMEBREW_CELLAR.exist?
|
||||
ff.each do |f|
|
||||
missing = f.missing_dependencies(hide: args.hide)
|
||||
next if missing.empty?
|
||||
|
||||
ff = if args.no_named?
|
||||
Formula.installed.sort
|
||||
else
|
||||
args.named.to_resolved_formulae.sort
|
||||
end
|
||||
|
||||
ff.each do |f|
|
||||
missing = f.missing_dependencies(hide: args.hide)
|
||||
next if missing.empty?
|
||||
|
||||
Homebrew.failed = true
|
||||
print "#{f}: " if ff.size > 1
|
||||
puts missing.join(" ")
|
||||
Homebrew.failed = true
|
||||
print "#{f}: " if ff.size > 1
|
||||
puts missing.join(" ")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,69 +1,68 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class NodenvSync < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Create symlinks for Homebrew's installed NodeJS versions in `~/.nodenv/versions`.
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def nodenv_sync_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Create symlinks for Homebrew's installed NodeJS versions in `~/.nodenv/versions`.
|
||||
Note that older version symlinks will also be created so e.g. NodeJS 19.1.0 will
|
||||
also be symlinked to 19.0.0.
|
||||
EOS
|
||||
|
||||
Note that older version symlinks will also be created so e.g. NodeJS 19.1.0 will
|
||||
also be symlinked to 19.0.0.
|
||||
EOS
|
||||
named_args :none
|
||||
end
|
||||
|
||||
named_args :none
|
||||
end
|
||||
end
|
||||
sig { override.void }
|
||||
def run
|
||||
nodenv_root = Pathname(ENV.fetch("HOMEBREW_NODENV_ROOT", Pathname(Dir.home)/".nodenv"))
|
||||
|
||||
sig { void }
|
||||
def nodenv_sync
|
||||
nodenv_root = Pathname(ENV.fetch("HOMEBREW_NODENV_ROOT", Pathname(Dir.home)/".nodenv"))
|
||||
# Don't run multiple times at once.
|
||||
nodenv_sync_running = nodenv_root/".nodenv_sync_running"
|
||||
return if nodenv_sync_running.exist?
|
||||
|
||||
# Don't run multiple times at once.
|
||||
nodenv_sync_running = nodenv_root/".nodenv_sync_running"
|
||||
return if nodenv_sync_running.exist?
|
||||
begin
|
||||
nodenv_versions = nodenv_root/"versions"
|
||||
nodenv_versions.mkpath
|
||||
FileUtils.touch nodenv_sync_running
|
||||
|
||||
begin
|
||||
nodenv_versions = nodenv_root/"versions"
|
||||
nodenv_versions.mkpath
|
||||
FileUtils.touch nodenv_sync_running
|
||||
HOMEBREW_CELLAR.glob("node{,@*}")
|
||||
.flat_map(&:children)
|
||||
.each { |path| link_nodenv_versions(path, nodenv_versions) }
|
||||
|
||||
nodenv_sync_args.parse
|
||||
nodenv_versions.children
|
||||
.select(&:symlink?)
|
||||
.reject(&:exist?)
|
||||
.each { |path| FileUtils.rm_f path }
|
||||
ensure
|
||||
nodenv_sync_running.unlink if nodenv_sync_running.exist?
|
||||
end
|
||||
end
|
||||
|
||||
HOMEBREW_CELLAR.glob("node{,@*}")
|
||||
.flat_map(&:children)
|
||||
.each { |path| link_nodenv_versions(path, nodenv_versions) }
|
||||
private
|
||||
|
||||
nodenv_versions.children
|
||||
.select(&:symlink?)
|
||||
.reject(&:exist?)
|
||||
.each { |path| FileUtils.rm_f path }
|
||||
ensure
|
||||
nodenv_sync_running.unlink if nodenv_sync_running.exist?
|
||||
end
|
||||
end
|
||||
sig { params(path: Pathname, nodenv_versions: Pathname).void }
|
||||
def link_nodenv_versions(path, nodenv_versions)
|
||||
nodenv_versions.mkpath
|
||||
|
||||
sig { params(path: Pathname, nodenv_versions: Pathname).void }
|
||||
def link_nodenv_versions(path, nodenv_versions)
|
||||
nodenv_versions.mkpath
|
||||
version = Keg.new(path).version
|
||||
major_version = version.major.to_i
|
||||
minor_version = version.minor.to_i || 0
|
||||
patch_version = version.patch.to_i || 0
|
||||
|
||||
version = Keg.new(path).version
|
||||
major_version = version.major.to_i
|
||||
minor_version = version.minor.to_i || 0
|
||||
patch_version = version.patch.to_i || 0
|
||||
(0..minor_version).each do |minor|
|
||||
(0..patch_version).each do |patch|
|
||||
link_path = nodenv_versions/"#{major_version}.#{minor}.#{patch}"
|
||||
|
||||
(0..minor_version).each do |minor|
|
||||
(0..patch_version).each do |patch|
|
||||
link_path = nodenv_versions/"#{major_version}.#{minor}.#{patch}"
|
||||
|
||||
FileUtils.rm_f link_path
|
||||
FileUtils.ln_sf path, link_path
|
||||
FileUtils.rm_f link_path
|
||||
FileUtils.ln_sf path, link_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,70 +1,71 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "options"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class OptionsCmd < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Show install options specific to <formula>.
|
||||
EOS
|
||||
switch "--compact",
|
||||
description: "Show all options on a single line separated by spaces."
|
||||
switch "--installed",
|
||||
description: "Show options for formulae that are currently installed."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not, to show their " \
|
||||
"options."
|
||||
flag "--command=",
|
||||
description: "Show options for the specified <command>."
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def options_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Show install options specific to <formula>.
|
||||
EOS
|
||||
switch "--compact",
|
||||
description: "Show all options on a single line separated by spaces."
|
||||
switch "--installed",
|
||||
description: "Show options for formulae that are currently installed."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not, to show their " \
|
||||
"options."
|
||||
flag "--command=",
|
||||
description: "Show options for the specified <command>."
|
||||
conflicts "--installed", "--all", "--command"
|
||||
|
||||
conflicts "--installed", "--all", "--command"
|
||||
|
||||
named_args :formula
|
||||
end
|
||||
end
|
||||
|
||||
def options
|
||||
args = options_args.parse
|
||||
|
||||
all = args.eval_all?
|
||||
|
||||
if all
|
||||
puts_options(Formula.all(eval_all: args.eval_all?).sort, args:)
|
||||
elsif args.installed?
|
||||
puts_options(Formula.installed.sort, args:)
|
||||
elsif args.command.present?
|
||||
cmd_options = Commands.command_options(args.command)
|
||||
odie "Unknown command: #{args.command}" if cmd_options.nil?
|
||||
|
||||
if args.compact?
|
||||
puts cmd_options.sort.map(&:first) * " "
|
||||
else
|
||||
cmd_options.sort.each { |option, desc| puts "#{option}\n\t#{desc}" }
|
||||
puts
|
||||
named_args :formula
|
||||
end
|
||||
elsif args.no_named?
|
||||
raise FormulaUnspecifiedError
|
||||
else
|
||||
puts_options args.named.to_formulae, args:
|
||||
end
|
||||
end
|
||||
|
||||
def puts_options(formulae, args:)
|
||||
formulae.each do |f|
|
||||
next if f.options.empty?
|
||||
sig { override.void }
|
||||
def run
|
||||
all = args.eval_all?
|
||||
|
||||
if args.compact?
|
||||
puts f.options.as_flags.sort * " "
|
||||
else
|
||||
puts f.full_name if formulae.length > 1
|
||||
Options.dump_for_formula f
|
||||
puts
|
||||
if all
|
||||
puts_options(Formula.all(eval_all: args.eval_all?).sort)
|
||||
elsif args.installed?
|
||||
puts_options(Formula.installed.sort)
|
||||
elsif args.command.present?
|
||||
cmd_options = Commands.command_options(T.must(args.command))
|
||||
odie "Unknown command: #{args.command}" if cmd_options.nil?
|
||||
|
||||
if args.compact?
|
||||
puts cmd_options.sort.map(&:first) * " "
|
||||
else
|
||||
cmd_options.sort.each { |option, desc| puts "#{option}\n\t#{desc}" }
|
||||
puts
|
||||
end
|
||||
elsif args.no_named?
|
||||
raise FormulaUnspecifiedError
|
||||
else
|
||||
puts_options args.named.to_formulae
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def puts_options(formulae)
|
||||
formulae.each do |f|
|
||||
next if f.options.empty?
|
||||
|
||||
if args.compact?
|
||||
puts f.options.as_flags.sort * " "
|
||||
else
|
||||
puts f.full_name if formulae.length > 1
|
||||
Options.dump_for_formula f
|
||||
puts
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,200 +1,202 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "keg"
|
||||
require "cli/parser"
|
||||
require "cask/caskroom"
|
||||
require "api"
|
||||
|
||||
module Homebrew
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.outdated_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
List installed casks and formulae that have an updated version available. By default, version
|
||||
information is displayed in interactive shells, and suppressed otherwise.
|
||||
EOS
|
||||
switch "-q", "--quiet",
|
||||
description: "List only the names of outdated kegs (takes precedence over `--verbose`)."
|
||||
switch "-v", "--verbose",
|
||||
description: "Include detailed version information."
|
||||
switch "--formula", "--formulae",
|
||||
description: "List only outdated formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "List only outdated casks."
|
||||
flag "--json",
|
||||
description: "Print output in JSON format. There are two versions: `v1` and `v2`. " \
|
||||
"`v1` is deprecated and is currently the default if no version is specified. " \
|
||||
"`v2` prints outdated formulae and casks."
|
||||
switch "--fetch-HEAD",
|
||||
description: "Fetch the upstream repository to detect if the HEAD installation of the " \
|
||||
"formula is outdated. Otherwise, the repository's HEAD will only be checked for " \
|
||||
"updates when a new stable or development version has been released."
|
||||
switch "-g", "--greedy",
|
||||
description: "Also include outdated casks with `auto_updates true` or `version :latest`."
|
||||
module Cmd
|
||||
class Outdated < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
List installed casks and formulae that have an updated version available. By default, version
|
||||
information is displayed in interactive shells, and suppressed otherwise.
|
||||
EOS
|
||||
switch "-q", "--quiet",
|
||||
description: "List only the names of outdated kegs (takes precedence over `--verbose`)."
|
||||
switch "-v", "--verbose",
|
||||
description: "Include detailed version information."
|
||||
switch "--formula", "--formulae",
|
||||
description: "List only outdated formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "List only outdated casks."
|
||||
flag "--json",
|
||||
description: "Print output in JSON format. There are two versions: `v1` and `v2`. " \
|
||||
"`v1` is deprecated and is currently the default if no version is specified. " \
|
||||
"`v2` prints outdated formulae and casks."
|
||||
switch "--fetch-HEAD",
|
||||
description: "Fetch the upstream repository to detect if the HEAD installation of the " \
|
||||
"formula is outdated. Otherwise, the repository's HEAD will only be checked for " \
|
||||
"updates when a new stable or development version has been released."
|
||||
switch "-g", "--greedy",
|
||||
description: "Also include outdated casks with `auto_updates true` or `version :latest`."
|
||||
|
||||
switch "--greedy-latest",
|
||||
description: "Also include outdated casks including those with `version :latest`."
|
||||
switch "--greedy-latest",
|
||||
description: "Also include outdated casks including those with `version :latest`."
|
||||
|
||||
switch "--greedy-auto-updates",
|
||||
description: "Also include outdated casks including those with `auto_updates true`."
|
||||
switch "--greedy-auto-updates",
|
||||
description: "Also include outdated casks including those with `auto_updates true`."
|
||||
|
||||
conflicts "--quiet", "--verbose", "--json"
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--quiet", "--verbose", "--json"
|
||||
conflicts "--formula", "--cask"
|
||||
|
||||
named_args [:formula, :cask]
|
||||
end
|
||||
end
|
||||
|
||||
def self.outdated
|
||||
args = outdated_args.parse
|
||||
|
||||
case json_version(args.json)
|
||||
when :v1
|
||||
odie "`brew outdated --json=v1` is no longer supported. Use brew outdated --json=v2 instead."
|
||||
when :v2, :default
|
||||
formulae, casks = if args.formula?
|
||||
[outdated_formulae(args:), []]
|
||||
elsif args.cask?
|
||||
[[], outdated_casks(args:)]
|
||||
else
|
||||
outdated_formulae_casks(args:)
|
||||
named_args [:formula, :cask]
|
||||
end
|
||||
|
||||
json = {
|
||||
"formulae" => json_info(formulae, args:),
|
||||
"casks" => json_info(casks, args:),
|
||||
}
|
||||
puts JSON.pretty_generate(json)
|
||||
|
||||
outdated = formulae + casks
|
||||
|
||||
else
|
||||
outdated = if args.formula?
|
||||
outdated_formulae(args:)
|
||||
elsif args.cask?
|
||||
outdated_casks(args:)
|
||||
else
|
||||
outdated_formulae_casks(args:).flatten
|
||||
end
|
||||
|
||||
print_outdated(outdated, args:)
|
||||
end
|
||||
|
||||
Homebrew.failed = args.named.present? && outdated.present?
|
||||
end
|
||||
|
||||
def self.print_outdated(formulae_or_casks, args:)
|
||||
formulae_or_casks.each do |formula_or_cask|
|
||||
if formula_or_cask.is_a?(Formula)
|
||||
f = formula_or_cask
|
||||
|
||||
if verbose?
|
||||
outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?)
|
||||
|
||||
current_version = if f.alias_changed? && !f.latest_formula.latest_version_installed?
|
||||
latest = f.latest_formula
|
||||
"#{latest.name} (#{latest.pkg_version})"
|
||||
elsif f.head? && outdated_kegs.any? { |k| k.version.to_s == f.pkg_version.to_s }
|
||||
# There is a newer HEAD but the version number has not changed.
|
||||
"latest HEAD"
|
||||
sig { override.void }
|
||||
def run
|
||||
case json_version(args.json)
|
||||
when :v1
|
||||
odie "`brew outdated --json=v1` is no longer supported. Use brew outdated --json=v2 instead."
|
||||
when :v2, :default
|
||||
formulae, casks = if args.formula?
|
||||
[outdated_formulae, []]
|
||||
elsif args.cask?
|
||||
[[], outdated_casks]
|
||||
else
|
||||
f.pkg_version.to_s
|
||||
outdated_formulae_casks
|
||||
end
|
||||
|
||||
outdated_versions = outdated_kegs.group_by { |keg| Formulary.from_keg(keg).full_name }
|
||||
.sort_by { |full_name, _kegs| full_name }
|
||||
.map do |full_name, kegs|
|
||||
"#{full_name} (#{kegs.map(&:version).join(", ")})"
|
||||
end.join(", ")
|
||||
json = {
|
||||
"formulae" => json_info(formulae),
|
||||
"casks" => json_info(casks),
|
||||
}
|
||||
puts JSON.pretty_generate(json)
|
||||
|
||||
pinned_version = " [pinned at #{f.pinned_version}]" if f.pinned?
|
||||
outdated = formulae + casks
|
||||
|
||||
puts "#{outdated_versions} < #{current_version}#{pinned_version}"
|
||||
else
|
||||
puts f.full_installed_specified_name
|
||||
end
|
||||
else
|
||||
c = formula_or_cask
|
||||
outdated = if args.formula?
|
||||
outdated_formulae
|
||||
elsif args.cask?
|
||||
outdated_casks
|
||||
else
|
||||
outdated_formulae_casks.flatten
|
||||
end
|
||||
|
||||
puts c.outdated_info(args.greedy?, verbose?, false, args.greedy_latest?, args.greedy_auto_updates?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.json_info(formulae_or_casks, args:)
|
||||
formulae_or_casks.map do |formula_or_cask|
|
||||
if formula_or_cask.is_a?(Formula)
|
||||
f = formula_or_cask
|
||||
|
||||
outdated_versions = f.outdated_kegs(fetch_head: args.fetch_HEAD?).map(&:version)
|
||||
current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s }
|
||||
"HEAD"
|
||||
else
|
||||
f.pkg_version.to_s
|
||||
print_outdated(outdated)
|
||||
end
|
||||
|
||||
{ name: f.full_name,
|
||||
installed_versions: outdated_versions.map(&:to_s),
|
||||
current_version:,
|
||||
pinned: f.pinned?,
|
||||
pinned_version: f.pinned_version }
|
||||
else
|
||||
c = formula_or_cask
|
||||
|
||||
c.outdated_info(args.greedy?, verbose?, true, args.greedy_latest?, args.greedy_auto_updates?)
|
||||
Homebrew.failed = args.named.present? && outdated.present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.verbose?
|
||||
($stdout.tty? || super) && !quiet?
|
||||
end
|
||||
private
|
||||
|
||||
def self.json_version(version)
|
||||
version_hash = {
|
||||
nil => nil,
|
||||
true => :default,
|
||||
"v1" => :v1,
|
||||
"v2" => :v2,
|
||||
}
|
||||
def print_outdated(formulae_or_casks)
|
||||
formulae_or_casks.each do |formula_or_cask|
|
||||
if formula_or_cask.is_a?(Formula)
|
||||
f = formula_or_cask
|
||||
|
||||
raise UsageError, "invalid JSON version: #{version}" unless version_hash.include?(version)
|
||||
if verbose?
|
||||
outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?)
|
||||
|
||||
version_hash[version]
|
||||
end
|
||||
current_version = if f.alias_changed? && !f.latest_formula.latest_version_installed?
|
||||
latest = f.latest_formula
|
||||
"#{latest.name} (#{latest.pkg_version})"
|
||||
elsif f.head? && outdated_kegs.any? { |k| k.version.to_s == f.pkg_version.to_s }
|
||||
# There is a newer HEAD but the version number has not changed.
|
||||
"latest HEAD"
|
||||
else
|
||||
f.pkg_version.to_s
|
||||
end
|
||||
|
||||
def self.outdated_formulae(args:)
|
||||
select_outdated((args.named.to_resolved_formulae.presence || Formula.installed), args:).sort
|
||||
end
|
||||
outdated_versions = outdated_kegs.group_by { |keg| Formulary.from_keg(keg).full_name }
|
||||
.sort_by { |full_name, _kegs| full_name }
|
||||
.map do |full_name, kegs|
|
||||
"#{full_name} (#{kegs.map(&:version).join(", ")})"
|
||||
end.join(", ")
|
||||
|
||||
def self.outdated_casks(args:)
|
||||
if args.named.present?
|
||||
select_outdated(args.named.to_casks, args:)
|
||||
else
|
||||
select_outdated(Cask::Caskroom.casks, args:)
|
||||
end
|
||||
end
|
||||
pinned_version = " [pinned at #{f.pinned_version}]" if f.pinned?
|
||||
|
||||
def self.outdated_formulae_casks(args:)
|
||||
formulae, casks = args.named.to_resolved_formulae_to_casks
|
||||
puts "#{outdated_versions} < #{current_version}#{pinned_version}"
|
||||
else
|
||||
puts f.full_installed_specified_name
|
||||
end
|
||||
else
|
||||
c = formula_or_cask
|
||||
|
||||
if formulae.blank? && casks.blank?
|
||||
formulae = Formula.installed
|
||||
casks = Cask::Caskroom.casks
|
||||
end
|
||||
puts c.outdated_info(args.greedy?, verbose?, false, args.greedy_latest?, args.greedy_auto_updates?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[select_outdated(formulae, args:).sort, select_outdated(casks, args:)]
|
||||
end
|
||||
def json_info(formulae_or_casks)
|
||||
formulae_or_casks.map do |formula_or_cask|
|
||||
if formula_or_cask.is_a?(Formula)
|
||||
f = formula_or_cask
|
||||
|
||||
def self.select_outdated(formulae_or_casks, args:)
|
||||
formulae_or_casks.select do |formula_or_cask|
|
||||
if formula_or_cask.is_a?(Formula)
|
||||
formula_or_cask.outdated?(fetch_head: args.fetch_HEAD?)
|
||||
else
|
||||
formula_or_cask.outdated?(greedy: args.greedy?, greedy_latest: args.greedy_latest?,
|
||||
greedy_auto_updates: args.greedy_auto_updates?)
|
||||
outdated_versions = f.outdated_kegs(fetch_head: args.fetch_HEAD?).map(&:version)
|
||||
current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s }
|
||||
"HEAD"
|
||||
else
|
||||
f.pkg_version.to_s
|
||||
end
|
||||
|
||||
{ name: f.full_name,
|
||||
installed_versions: outdated_versions.map(&:to_s),
|
||||
current_version:,
|
||||
pinned: f.pinned?,
|
||||
pinned_version: f.pinned_version }
|
||||
else
|
||||
c = formula_or_cask
|
||||
|
||||
c.outdated_info(args.greedy?, verbose?, true, args.greedy_latest?, args.greedy_auto_updates?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def verbose?
|
||||
($stdout.tty? || Context.current.verbose?) && !Context.current.quiet?
|
||||
end
|
||||
|
||||
def json_version(version)
|
||||
version_hash = {
|
||||
nil => nil,
|
||||
true => :default,
|
||||
"v1" => :v1,
|
||||
"v2" => :v2,
|
||||
}
|
||||
|
||||
raise UsageError, "invalid JSON version: #{version}" unless version_hash.include?(version)
|
||||
|
||||
version_hash[version]
|
||||
end
|
||||
|
||||
def outdated_formulae
|
||||
select_outdated((args.named.to_resolved_formulae.presence || Formula.installed)).sort
|
||||
end
|
||||
|
||||
def outdated_casks
|
||||
if args.named.present?
|
||||
select_outdated(args.named.to_casks)
|
||||
else
|
||||
select_outdated(Cask::Caskroom.casks)
|
||||
end
|
||||
end
|
||||
|
||||
def outdated_formulae_casks
|
||||
formulae, casks = args.named.to_resolved_formulae_to_casks
|
||||
|
||||
if formulae.blank? && casks.blank?
|
||||
formulae = Formula.installed
|
||||
casks = Cask::Caskroom.casks
|
||||
end
|
||||
|
||||
[select_outdated(formulae).sort, select_outdated(casks)]
|
||||
end
|
||||
|
||||
def select_outdated(formulae_or_casks)
|
||||
formulae_or_casks.select do |formula_or_cask|
|
||||
if formula_or_cask.is_a?(Formula)
|
||||
formula_or_cask.outdated?(fetch_head: args.fetch_HEAD?)
|
||||
else
|
||||
formula_or_cask.outdated?(greedy: args.greedy?, greedy_latest: args.greedy_latest?,
|
||||
greedy_auto_updates: args.greedy_auto_updates?)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,37 +1,35 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "cli/parser"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Pin < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Pin the specified <formula>, preventing them from being upgraded when
|
||||
issuing the `brew upgrade` <formula> command. See also `unpin`.
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def pin_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Pin the specified <formula>, preventing them from being upgraded when
|
||||
issuing the `brew upgrade` <formula> command. See also `unpin`.
|
||||
*Note:* Other packages which depend on newer versions of a pinned formula
|
||||
might not install or run correctly.
|
||||
EOS
|
||||
|
||||
*Note:* Other packages which depend on newer versions of a pinned formula
|
||||
might not install or run correctly.
|
||||
EOS
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
end
|
||||
|
||||
def pin
|
||||
args = pin_args.parse
|
||||
|
||||
args.named.to_resolved_formulae.each do |f|
|
||||
if f.pinned?
|
||||
opoo "#{f.name} already pinned"
|
||||
elsif !f.pinnable?
|
||||
onoe "#{f.name} not installed"
|
||||
else
|
||||
f.pin
|
||||
sig { override.void }
|
||||
def run
|
||||
args.named.to_resolved_formulae.each do |f|
|
||||
if f.pinned?
|
||||
opoo "#{f.name} already pinned"
|
||||
elsif !f.pinnable?
|
||||
onoe "#{f.name} not installed"
|
||||
else
|
||||
f.pin
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,169 +1,167 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class PostgresqlUpgradeDatabase < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Upgrades the database for the `postgresql` formula.
|
||||
EOS
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def postgresql_upgrade_database_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Upgrades the database for the `postgresql` formula.
|
||||
EOS
|
||||
named_args :none
|
||||
|
||||
named_args :none
|
||||
|
||||
hide_from_man_page!
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def postgresql_upgrade_database
|
||||
postgresql_upgrade_database_args.parse
|
||||
|
||||
odisabled "brew postgresql_upgrade_database",
|
||||
"using new, versioned e.g. `var/postgres@14` datadir and `pg_upgrade`"
|
||||
|
||||
name = "postgresql"
|
||||
pg = Formula[name]
|
||||
bin = pg.bin
|
||||
var = pg.var
|
||||
version = pg.version
|
||||
pg_version_file = var/"postgres/PG_VERSION"
|
||||
|
||||
pg_version_installed = version.to_s[/^\d+/]
|
||||
pg_version_data = pg_version_file.read.chomp
|
||||
if pg_version_installed == pg_version_data
|
||||
odie <<~EOS
|
||||
#{name} data already upgraded!
|
||||
EOS
|
||||
end
|
||||
|
||||
datadir = var/"postgres"
|
||||
old_datadir = var/"postgres.old"
|
||||
if old_datadir.exist?
|
||||
odie <<~EOS
|
||||
#{old_datadir} already exists!
|
||||
Remove it if you want to upgrade data automatically.
|
||||
EOS
|
||||
end
|
||||
|
||||
old_pg_name = "#{name}@#{pg_version_data}"
|
||||
old_pg_glob = "#{HOMEBREW_CELLAR}/#{old_pg_name}/#{pg_version_data}.*/bin"
|
||||
old_bin = Pathname.glob(old_pg_glob).first
|
||||
old_bin ||= begin
|
||||
Formula[old_pg_name]
|
||||
ohai "brew install #{old_pg_name}"
|
||||
system HOMEBREW_BREW_FILE, "install", old_pg_name
|
||||
Pathname.glob(old_pg_glob).first
|
||||
rescue FormulaUnavailableError
|
||||
nil
|
||||
end
|
||||
|
||||
odie "No #{name} #{pg_version_data}.* version installed!" unless old_bin
|
||||
|
||||
server_stopped = T.let(false, T::Boolean)
|
||||
moved_data = T.let(false, T::Boolean)
|
||||
initdb_run = T.let(false, T::Boolean)
|
||||
upgraded = T.let(false, T::Boolean)
|
||||
|
||||
begin
|
||||
# Following instructions from:
|
||||
# https://www.postgresql.org/docs/10/static/pgupgrade.html
|
||||
ohai "Upgrading #{name} data from #{pg_version_data} to #{pg_version_installed}..."
|
||||
services_json_output = Utils.popen_read(HOMEBREW_BREW_FILE, "services", "info", "--all", "--json")
|
||||
services_json = JSON.parse(services_json_output)
|
||||
loaded_service_names = services_json.select { |sj| sj[:loaded] }.map { |sj| sj[:name] }
|
||||
if loaded_service_names.include?(name)
|
||||
system HOMEBREW_BREW_FILE, "services", "stop", name
|
||||
service_stopped = true
|
||||
elsif quiet_system "#{bin}/pg_ctl", "-D", datadir, "status"
|
||||
system "#{bin}/pg_ctl", "-D", datadir, "stop"
|
||||
server_stopped = true
|
||||
hide_from_man_page!
|
||||
end
|
||||
|
||||
# Shut down old server if it is up via brew services
|
||||
system HOMEBREW_BREW_FILE, "services", "stop", old_pg_name if loaded_service_names.include?(old_pg_name)
|
||||
sig { override.void }
|
||||
def run
|
||||
odisabled "brew postgresql_upgrade_database",
|
||||
"using new, versioned e.g. `var/postgres@14` datadir and `pg_upgrade`"
|
||||
|
||||
# get 'lc_collate' from old DB"
|
||||
unless quiet_system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "status"
|
||||
system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "start"
|
||||
end
|
||||
name = "postgresql"
|
||||
pg = Formula[name]
|
||||
bin = pg.bin
|
||||
var = pg.var
|
||||
version = pg.version
|
||||
pg_version_file = var/"postgres/PG_VERSION"
|
||||
|
||||
initdb_args = T.let([], T::Array[String])
|
||||
locale_settings = %w[
|
||||
lc_collate
|
||||
lc_ctype
|
||||
lc_messages
|
||||
lc_monetary
|
||||
lc_numeric
|
||||
lc_time
|
||||
server_encoding
|
||||
]
|
||||
locale_settings.each do |setting|
|
||||
sql = "SELECT setting FROM pg_settings WHERE name LIKE '#{setting}';"
|
||||
value = Utils.popen_read("#{old_bin}/psql", "postgres", "-qtAX", "-U", ENV.fetch("USER"), "-c", sql).strip
|
||||
|
||||
next if value.empty?
|
||||
|
||||
initdb_args += if setting == "server_encoding"
|
||||
["-E #{value}"]
|
||||
else
|
||||
["--#{setting.tr("_", "-")}=#{value}"]
|
||||
pg_version_installed = version.to_s[/^\d+/]
|
||||
pg_version_data = pg_version_file.read.chomp
|
||||
if pg_version_installed == pg_version_data
|
||||
odie <<~EOS
|
||||
#{name} data already upgraded!
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
if quiet_system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "status"
|
||||
system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "stop"
|
||||
end
|
||||
|
||||
ohai "Moving #{name} data from #{datadir} to #{old_datadir}..."
|
||||
FileUtils.mv datadir, old_datadir
|
||||
moved_data = true
|
||||
|
||||
(var/"postgres").mkpath
|
||||
ohai "Creating database..."
|
||||
safe_system "#{bin}/initdb", *initdb_args, "#{var}/postgres"
|
||||
initdb_run = true
|
||||
|
||||
ohai "Migrating and upgrading data..."
|
||||
(var/"log").cd do
|
||||
safe_system "#{bin}/pg_upgrade",
|
||||
"-r",
|
||||
"-b", old_bin,
|
||||
"-B", bin,
|
||||
"-d", old_datadir,
|
||||
"-D", datadir,
|
||||
"-j", Hardware::CPU.cores.to_s
|
||||
end
|
||||
upgraded = true
|
||||
|
||||
ohai "Upgraded #{name} data from #{pg_version_data} to #{pg_version_installed}!"
|
||||
ohai "Your #{name} #{pg_version_data} data remains at #{old_datadir}"
|
||||
ensure
|
||||
if upgraded
|
||||
if server_stopped
|
||||
safe_system "#{bin}/pg_ctl", "-D", datadir, "start"
|
||||
elsif service_stopped
|
||||
safe_system HOMEBREW_BREW_FILE, "services", "start", name
|
||||
datadir = var/"postgres"
|
||||
old_datadir = var/"postgres.old"
|
||||
if old_datadir.exist?
|
||||
odie <<~EOS
|
||||
#{old_datadir} already exists!
|
||||
Remove it if you want to upgrade data automatically.
|
||||
EOS
|
||||
end
|
||||
else
|
||||
onoe "Upgrading #{name} data from #{pg_version_data} to #{pg_version_installed} failed!"
|
||||
if initdb_run
|
||||
ohai "Removing empty #{name} initdb database..."
|
||||
FileUtils.rm_r datadir
|
||||
|
||||
old_pg_name = "#{name}@#{pg_version_data}"
|
||||
old_pg_glob = "#{HOMEBREW_CELLAR}/#{old_pg_name}/#{pg_version_data}.*/bin"
|
||||
old_bin = Pathname.glob(old_pg_glob).first
|
||||
old_bin ||= begin
|
||||
Formula[old_pg_name]
|
||||
ohai "brew install #{old_pg_name}"
|
||||
system HOMEBREW_BREW_FILE, "install", old_pg_name
|
||||
Pathname.glob(old_pg_glob).first
|
||||
rescue FormulaUnavailableError
|
||||
nil
|
||||
end
|
||||
if moved_data
|
||||
ohai "Moving #{name} data back from #{old_datadir} to #{datadir}..."
|
||||
FileUtils.mv old_datadir, datadir
|
||||
end
|
||||
if server_stopped
|
||||
system "#{bin}/pg_ctl", "-D", datadir, "start"
|
||||
elsif service_stopped
|
||||
system HOMEBREW_BREW_FILE, "services", "start", name
|
||||
|
||||
odie "No #{name} #{pg_version_data}.* version installed!" unless old_bin
|
||||
|
||||
server_stopped = T.let(false, T::Boolean)
|
||||
moved_data = T.let(false, T::Boolean)
|
||||
initdb_run = T.let(false, T::Boolean)
|
||||
upgraded = T.let(false, T::Boolean)
|
||||
|
||||
begin
|
||||
# Following instructions from:
|
||||
# https://www.postgresql.org/docs/10/static/pgupgrade.html
|
||||
ohai "Upgrading #{name} data from #{pg_version_data} to #{pg_version_installed}..."
|
||||
services_json_output = Utils.popen_read(HOMEBREW_BREW_FILE, "services", "info", "--all", "--json")
|
||||
services_json = JSON.parse(services_json_output)
|
||||
loaded_service_names = services_json.select { |sj| sj[:loaded] }.map { |sj| sj[:name] }
|
||||
if loaded_service_names.include?(name)
|
||||
system HOMEBREW_BREW_FILE, "services", "stop", name
|
||||
service_stopped = true
|
||||
elsif quiet_system "#{bin}/pg_ctl", "-D", datadir, "status"
|
||||
system "#{bin}/pg_ctl", "-D", datadir, "stop"
|
||||
server_stopped = true
|
||||
end
|
||||
|
||||
# Shut down old server if it is up via brew services
|
||||
system HOMEBREW_BREW_FILE, "services", "stop", old_pg_name if loaded_service_names.include?(old_pg_name)
|
||||
|
||||
# get 'lc_collate' from old DB"
|
||||
unless quiet_system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "status"
|
||||
system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "start"
|
||||
end
|
||||
|
||||
initdb_args = T.let([], T::Array[String])
|
||||
locale_settings = %w[
|
||||
lc_collate
|
||||
lc_ctype
|
||||
lc_messages
|
||||
lc_monetary
|
||||
lc_numeric
|
||||
lc_time
|
||||
server_encoding
|
||||
]
|
||||
locale_settings.each do |setting|
|
||||
sql = "SELECT setting FROM pg_settings WHERE name LIKE '#{setting}';"
|
||||
value = Utils.popen_read("#{old_bin}/psql", "postgres", "-qtAX", "-U", ENV.fetch("USER"), "-c",
|
||||
sql).strip
|
||||
|
||||
next if value.empty?
|
||||
|
||||
initdb_args += if setting == "server_encoding"
|
||||
["-E #{value}"]
|
||||
else
|
||||
["--#{setting.tr("_", "-")}=#{value}"]
|
||||
end
|
||||
end
|
||||
|
||||
if quiet_system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "status"
|
||||
system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "stop"
|
||||
end
|
||||
|
||||
ohai "Moving #{name} data from #{datadir} to #{old_datadir}..."
|
||||
FileUtils.mv datadir, old_datadir
|
||||
moved_data = true
|
||||
|
||||
(var/"postgres").mkpath
|
||||
ohai "Creating database..."
|
||||
safe_system "#{bin}/initdb", *initdb_args, "#{var}/postgres"
|
||||
initdb_run = true
|
||||
|
||||
ohai "Migrating and upgrading data..."
|
||||
(var/"log").cd do
|
||||
safe_system "#{bin}/pg_upgrade",
|
||||
"-r",
|
||||
"-b", old_bin,
|
||||
"-B", bin,
|
||||
"-d", old_datadir,
|
||||
"-D", datadir,
|
||||
"-j", Hardware::CPU.cores.to_s
|
||||
end
|
||||
upgraded = true
|
||||
|
||||
ohai "Upgraded #{name} data from #{pg_version_data} to #{pg_version_installed}!"
|
||||
ohai "Your #{name} #{pg_version_data} data remains at #{old_datadir}"
|
||||
ensure
|
||||
if upgraded
|
||||
if server_stopped
|
||||
safe_system "#{bin}/pg_ctl", "-D", datadir, "start"
|
||||
elsif service_stopped
|
||||
safe_system HOMEBREW_BREW_FILE, "services", "start", name
|
||||
end
|
||||
else
|
||||
onoe "Upgrading #{name} data from #{pg_version_data} to #{pg_version_installed} failed!"
|
||||
if initdb_run
|
||||
ohai "Removing empty #{name} initdb database..."
|
||||
FileUtils.rm_r datadir
|
||||
end
|
||||
if moved_data
|
||||
ohai "Moving #{name} data back from #{old_datadir} to #{datadir}..."
|
||||
FileUtils.mv old_datadir, datadir
|
||||
end
|
||||
if server_stopped
|
||||
system "#{bin}/pg_ctl", "-D", datadir, "start"
|
||||
elsif service_stopped
|
||||
system HOMEBREW_BREW_FILE, "services", "start", name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,35 +1,33 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "sandbox"
|
||||
require "formula_installer"
|
||||
require "cli/parser"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Postinstall < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Rerun the post-install steps for <formula>.
|
||||
EOS
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def postinstall_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Rerun the post-install steps for <formula>.
|
||||
EOS
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
end
|
||||
|
||||
def postinstall
|
||||
args = postinstall_args.parse
|
||||
|
||||
args.named.to_resolved_formulae.each do |f|
|
||||
ohai "Postinstalling #{f}"
|
||||
f.install_etc_var
|
||||
if f.post_install_defined?
|
||||
fi = FormulaInstaller.new(f, **{ debug: args.debug?, quiet: args.quiet?, verbose: args.verbose? }.compact)
|
||||
fi.post_install
|
||||
else
|
||||
opoo "#{f}: no `post_install` method was defined in the formula!"
|
||||
sig { override.void }
|
||||
def run
|
||||
args.named.to_resolved_formulae.each do |f|
|
||||
ohai "Postinstalling #{f}"
|
||||
f.install_etc_var
|
||||
if f.post_install_defined?
|
||||
fi = FormulaInstaller.new(f, **{ debug: args.debug?, quiet: args.quiet?, verbose: args.verbose? }.compact)
|
||||
fi.post_install
|
||||
else
|
||||
opoo "#{f}: no `post_install` method was defined in the formula!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,68 +1,66 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class PyenvSync < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Create symlinks for Homebrew's installed Python versions in `~/.pyenv/versions`.
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def pyenv_sync_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Create symlinks for Homebrew's installed Python versions in `~/.pyenv/versions`.
|
||||
Note that older patch version symlinks will be created and linked to the minor
|
||||
version so e.g. Python 3.11.0 will also be symlinked to 3.11.3.
|
||||
EOS
|
||||
|
||||
Note that older patch version symlinks will be created and linked to the minor
|
||||
version so e.g. Python 3.11.0 will also be symlinked to 3.11.3.
|
||||
EOS
|
||||
named_args :none
|
||||
end
|
||||
|
||||
named_args :none
|
||||
end
|
||||
end
|
||||
sig { override.void }
|
||||
def run
|
||||
pyenv_root = Pathname(ENV.fetch("HOMEBREW_PYENV_ROOT", Pathname(Dir.home)/".pyenv"))
|
||||
|
||||
sig { void }
|
||||
def pyenv_sync
|
||||
pyenv_root = Pathname(ENV.fetch("HOMEBREW_PYENV_ROOT", Pathname(Dir.home)/".pyenv"))
|
||||
# Don't run multiple times at once.
|
||||
pyenv_sync_running = pyenv_root/".pyenv_sync_running"
|
||||
return if pyenv_sync_running.exist?
|
||||
|
||||
# Don't run multiple times at once.
|
||||
pyenv_sync_running = pyenv_root/".pyenv_sync_running"
|
||||
return if pyenv_sync_running.exist?
|
||||
begin
|
||||
pyenv_versions = pyenv_root/"versions"
|
||||
pyenv_versions.mkpath
|
||||
FileUtils.touch pyenv_sync_running
|
||||
HOMEBREW_CELLAR.glob("python{,@*}")
|
||||
.flat_map(&:children)
|
||||
.each { |path| link_pyenv_versions(path, pyenv_versions) }
|
||||
|
||||
begin
|
||||
pyenv_versions = pyenv_root/"versions"
|
||||
pyenv_versions.mkpath
|
||||
FileUtils.touch pyenv_sync_running
|
||||
pyenv_versions.children
|
||||
.select(&:symlink?)
|
||||
.reject(&:exist?)
|
||||
.each { |path| FileUtils.rm_f path }
|
||||
ensure
|
||||
pyenv_sync_running.unlink if pyenv_sync_running.exist?
|
||||
end
|
||||
end
|
||||
|
||||
pyenv_sync_args.parse
|
||||
private
|
||||
|
||||
HOMEBREW_CELLAR.glob("python{,@*}")
|
||||
.flat_map(&:children)
|
||||
.each { |path| link_pyenv_versions(path, pyenv_versions) }
|
||||
sig { params(path: Pathname, pyenv_versions: Pathname).void }
|
||||
def link_pyenv_versions(path, pyenv_versions)
|
||||
pyenv_versions.mkpath
|
||||
|
||||
pyenv_versions.children
|
||||
.select(&:symlink?)
|
||||
.reject(&:exist?)
|
||||
.each { |path| FileUtils.rm_f path }
|
||||
ensure
|
||||
pyenv_sync_running.unlink if pyenv_sync_running.exist?
|
||||
end
|
||||
end
|
||||
version = Keg.new(path).version
|
||||
major_version = version.major.to_i
|
||||
minor_version = version.minor.to_i
|
||||
patch_version = version.patch.to_i
|
||||
|
||||
sig { params(path: Pathname, pyenv_versions: Pathname).void }
|
||||
def link_pyenv_versions(path, pyenv_versions)
|
||||
pyenv_versions.mkpath
|
||||
(0..patch_version).each do |patch|
|
||||
link_path = pyenv_versions/"#{major_version}.#{minor_version}.#{patch}"
|
||||
|
||||
version = Keg.new(path).version
|
||||
major_version = version.major.to_i
|
||||
minor_version = version.minor.to_i
|
||||
patch_version = version.patch.to_i
|
||||
|
||||
(0..patch_version).each do |patch|
|
||||
link_path = pyenv_versions/"#{major_version}.#{minor_version}.#{patch}"
|
||||
|
||||
FileUtils.rm_f link_path
|
||||
FileUtils.ln_sf path, link_path
|
||||
FileUtils.rm_f link_path
|
||||
FileUtils.ln_sf path, link_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,68 +1,67 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class RbenvSync < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Create symlinks for Homebrew's installed Ruby versions in `~/.rbenv/versions`.
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def rbenv_sync_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Create symlinks for Homebrew's installed Ruby versions in `~/.rbenv/versions`.
|
||||
Note that older version symlinks will also be created so e.g. Ruby 3.2.1 will
|
||||
also be symlinked to 3.2.0.
|
||||
EOS
|
||||
|
||||
Note that older version symlinks will also be created so e.g. Ruby 3.2.1 will
|
||||
also be symlinked to 3.2.0.
|
||||
EOS
|
||||
named_args :none
|
||||
end
|
||||
|
||||
named_args :none
|
||||
end
|
||||
end
|
||||
sig { override.void }
|
||||
def run
|
||||
rbenv_root = Pathname(ENV.fetch("HOMEBREW_RBENV_ROOT", Pathname(Dir.home)/".rbenv"))
|
||||
|
||||
sig { void }
|
||||
def rbenv_sync
|
||||
rbenv_root = Pathname(ENV.fetch("HOMEBREW_RBENV_ROOT", Pathname(Dir.home)/".rbenv"))
|
||||
# Don't run multiple times at once.
|
||||
rbenv_sync_running = rbenv_root/".rbenv_sync_running"
|
||||
return if rbenv_sync_running.exist?
|
||||
|
||||
# Don't run multiple times at once.
|
||||
rbenv_sync_running = rbenv_root/".rbenv_sync_running"
|
||||
return if rbenv_sync_running.exist?
|
||||
begin
|
||||
rbenv_versions = rbenv_root/"versions"
|
||||
rbenv_versions.mkpath
|
||||
FileUtils.touch rbenv_sync_running
|
||||
|
||||
begin
|
||||
rbenv_versions = rbenv_root/"versions"
|
||||
rbenv_versions.mkpath
|
||||
FileUtils.touch rbenv_sync_running
|
||||
HOMEBREW_CELLAR.glob("ruby{,@*}")
|
||||
.flat_map(&:children)
|
||||
.each { |path| link_rbenv_versions(path, rbenv_versions) }
|
||||
|
||||
rbenv_sync_args.parse
|
||||
rbenv_versions.children
|
||||
.select(&:symlink?)
|
||||
.reject(&:exist?)
|
||||
.each { |path| FileUtils.rm_f path }
|
||||
ensure
|
||||
rbenv_sync_running.unlink if rbenv_sync_running.exist?
|
||||
end
|
||||
end
|
||||
|
||||
HOMEBREW_CELLAR.glob("ruby{,@*}")
|
||||
.flat_map(&:children)
|
||||
.each { |path| link_rbenv_versions(path, rbenv_versions) }
|
||||
private
|
||||
|
||||
rbenv_versions.children
|
||||
.select(&:symlink?)
|
||||
.reject(&:exist?)
|
||||
.each { |path| FileUtils.rm_f path }
|
||||
ensure
|
||||
rbenv_sync_running.unlink if rbenv_sync_running.exist?
|
||||
end
|
||||
end
|
||||
sig { params(path: Pathname, rbenv_versions: Pathname).void }
|
||||
def link_rbenv_versions(path, rbenv_versions)
|
||||
rbenv_versions.mkpath
|
||||
|
||||
sig { params(path: Pathname, rbenv_versions: Pathname).void }
|
||||
def link_rbenv_versions(path, rbenv_versions)
|
||||
rbenv_versions.mkpath
|
||||
version = Keg.new(path).version
|
||||
major_version = version.major.to_i
|
||||
minor_version = version.minor.to_i
|
||||
patch_version = version.patch.to_i || 0
|
||||
|
||||
version = Keg.new(path).version
|
||||
major_version = version.major.to_i
|
||||
minor_version = version.minor.to_i
|
||||
patch_version = version.patch.to_i || 0
|
||||
(0..patch_version).each do |patch|
|
||||
link_path = rbenv_versions/"#{major_version}.#{minor_version}.#{patch}"
|
||||
|
||||
(0..patch_version).each do |patch|
|
||||
link_path = rbenv_versions/"#{major_version}.#{minor_version}.#{patch}"
|
||||
|
||||
FileUtils.rm_f link_path
|
||||
FileUtils.ln_sf path, link_path
|
||||
FileUtils.rm_f link_path
|
||||
FileUtils.ln_sf path, link_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,69 +1,67 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "readall"
|
||||
require "cli/parser"
|
||||
require "env_config"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class ReadallCmd < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Import all items from the specified <tap>, or from all installed taps if none is provided.
|
||||
This can be useful for debugging issues across all items when making
|
||||
significant changes to `formula.rb`, testing the performance of loading
|
||||
all items or checking if any current formulae/casks have Ruby issues.
|
||||
EOS
|
||||
flag "--os=",
|
||||
description: "Read using the given operating system. (Pass `all` to simulate all operating systems.)"
|
||||
flag "--arch=",
|
||||
description: "Read using the given CPU architecture. (Pass `all` to simulate all architectures.)"
|
||||
switch "--aliases",
|
||||
description: "Verify any alias symlinks in each tap."
|
||||
switch "--syntax",
|
||||
description: "Syntax-check all of Homebrew's Ruby files (if no <tap> is passed)."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not. " \
|
||||
"Implied if `HOMEBREW_EVAL_ALL` is set."
|
||||
switch "--no-simulate",
|
||||
description: "Don't simulate other system configurations when checking formulae and casks."
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def readall_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Import all items from the specified <tap>, or from all installed taps if none is provided.
|
||||
This can be useful for debugging issues across all items when making
|
||||
significant changes to `formula.rb`, testing the performance of loading
|
||||
all items or checking if any current formulae/casks have Ruby issues.
|
||||
EOS
|
||||
flag "--os=",
|
||||
description: "Read using the given operating system. (Pass `all` to simulate all operating systems.)"
|
||||
flag "--arch=",
|
||||
description: "Read using the given CPU architecture. (Pass `all` to simulate all architectures.)"
|
||||
switch "--aliases",
|
||||
description: "Verify any alias symlinks in each tap."
|
||||
switch "--syntax",
|
||||
description: "Syntax-check all of Homebrew's Ruby files (if no <tap> is passed)."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not. " \
|
||||
"Implied if `HOMEBREW_EVAL_ALL` is set."
|
||||
switch "--no-simulate",
|
||||
description: "Don't simulate other system configurations when checking formulae and casks."
|
||||
|
||||
named_args :tap
|
||||
end
|
||||
end
|
||||
|
||||
def readall
|
||||
args = readall_args.parse
|
||||
|
||||
Homebrew.with_no_api_env do
|
||||
if args.syntax? && args.no_named?
|
||||
scan_files = "#{HOMEBREW_LIBRARY_PATH}/**/*.rb"
|
||||
ruby_files = Dir.glob(scan_files).grep_v(%r{/(vendor)/})
|
||||
|
||||
Homebrew.failed = true unless Readall.valid_ruby_syntax?(ruby_files)
|
||||
named_args :tap
|
||||
end
|
||||
|
||||
options = {
|
||||
aliases: args.aliases?,
|
||||
no_simulate: args.no_simulate?,
|
||||
}
|
||||
options[:os_arch_combinations] = args.os_arch_combinations if args.os || args.arch
|
||||
sig { override.void }
|
||||
def run
|
||||
Homebrew.with_no_api_env do
|
||||
if args.syntax? && args.no_named?
|
||||
scan_files = "#{HOMEBREW_LIBRARY_PATH}/**/*.rb"
|
||||
ruby_files = Dir.glob(scan_files).grep_v(%r{/(vendor)/})
|
||||
|
||||
taps = if args.no_named?
|
||||
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
|
||||
raise UsageError, "`brew readall` needs a tap or `--eval-all` passed or `HOMEBREW_EVAL_ALL` set!"
|
||||
Homebrew.failed = true unless Readall.valid_ruby_syntax?(ruby_files)
|
||||
end
|
||||
|
||||
options = {
|
||||
aliases: args.aliases?,
|
||||
no_simulate: args.no_simulate?,
|
||||
}
|
||||
options[:os_arch_combinations] = args.os_arch_combinations if args.os || args.arch
|
||||
|
||||
taps = if args.no_named?
|
||||
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
|
||||
raise UsageError, "`brew readall` needs a tap or `--eval-all` passed or `HOMEBREW_EVAL_ALL` set!"
|
||||
end
|
||||
|
||||
Tap.installed
|
||||
else
|
||||
args.named.to_installed_taps
|
||||
end
|
||||
|
||||
taps.each do |tap|
|
||||
Homebrew.failed = true unless Readall.valid_tap?(tap, **options)
|
||||
end
|
||||
end
|
||||
|
||||
Tap.installed
|
||||
else
|
||||
args.named.to_installed_taps
|
||||
end
|
||||
|
||||
taps.each do |tap|
|
||||
Homebrew.failed = true unless Readall.valid_tap?(tap, **options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula_installer"
|
||||
require "development_tools"
|
||||
require "messages"
|
||||
require "install"
|
||||
require "reinstall"
|
||||
require "cli/parser"
|
||||
require "cleanup"
|
||||
require "cask/utils"
|
||||
require "cask/macos"
|
||||
@ -15,172 +15,174 @@ require "upgrade"
|
||||
require "api"
|
||||
|
||||
module Homebrew
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.reinstall_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Uninstall and then reinstall a <formula> or <cask> using the same options it was
|
||||
originally installed with, plus any appended options specific to a <formula>.
|
||||
module Cmd
|
||||
class Reinstall < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Uninstall and then reinstall a <formula> or <cask> using the same options it was
|
||||
originally installed with, plus any appended options specific to a <formula>.
|
||||
|
||||
Unless `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK` is set, `brew upgrade` or `brew reinstall` will be run for
|
||||
outdated dependents and dependents with broken linkage, respectively.
|
||||
Unless `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK` is set, `brew upgrade` or `brew reinstall` will be run for
|
||||
outdated dependents and dependents with broken linkage, respectively.
|
||||
|
||||
Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the
|
||||
reinstalled formulae or, every 30 days, for all formulae.
|
||||
EOS
|
||||
switch "-d", "--debug",
|
||||
description: "If brewing fails, open an interactive debugging session with access to IRB " \
|
||||
"or a shell inside the temporary build directory."
|
||||
switch "-f", "--force",
|
||||
description: "Install without checking for previously installed keg-only or " \
|
||||
"non-migrated versions."
|
||||
switch "-v", "--verbose",
|
||||
description: "Print the verification and post-install steps."
|
||||
[
|
||||
[:switch, "--formula", "--formulae", { description: "Treat all named arguments as formulae." }],
|
||||
[:switch, "-s", "--build-from-source", {
|
||||
description: "Compile <formula> from source even if a bottle is available.",
|
||||
}],
|
||||
[:switch, "-i", "--interactive", {
|
||||
description: "Download and patch <formula>, then open a shell. This allows the user to " \
|
||||
"run `./configure --help` and otherwise determine how to turn the software " \
|
||||
"package into a Homebrew package.",
|
||||
}],
|
||||
[:switch, "--force-bottle", {
|
||||
description: "Install from a bottle if it exists for the current or newest version of " \
|
||||
"macOS, even if it would not normally be used for installation.",
|
||||
}],
|
||||
[:switch, "--keep-tmp", {
|
||||
description: "Retain the temporary files created during installation.",
|
||||
}],
|
||||
[:switch, "--debug-symbols", {
|
||||
depends_on: "--build-from-source",
|
||||
description: "Generate debug symbols on build. Source will be retained in a cache directory.",
|
||||
}],
|
||||
[:switch, "--display-times", {
|
||||
env: :display_install_times,
|
||||
description: "Print install times for each formula at the end of the run.",
|
||||
}],
|
||||
[:switch, "-g", "--git", {
|
||||
description: "Create a Git repository, useful for creating patches to the software.",
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--cask", args.last
|
||||
end
|
||||
formula_options
|
||||
[
|
||||
[:switch, "--cask", "--casks", { description: "Treat all named arguments as casks." }],
|
||||
[:switch, "--[no-]binaries", {
|
||||
description: "Disable/enable linking of helper executables (default: enabled).",
|
||||
env: :cask_opts_binaries,
|
||||
}],
|
||||
[:switch, "--require-sha", {
|
||||
description: "Require all casks to have a checksum.",
|
||||
env: :cask_opts_require_sha,
|
||||
}],
|
||||
[:switch, "--[no-]quarantine", {
|
||||
description: "Disable/enable quarantining of downloads (default: enabled).",
|
||||
env: :cask_opts_quarantine,
|
||||
}],
|
||||
[:switch, "--adopt", {
|
||||
description: "Adopt existing artifacts in the destination that are identical to those being installed. " \
|
||||
"Cannot be combined with `--force`.",
|
||||
}],
|
||||
[:switch, "--skip-cask-deps", {
|
||||
description: "Skip installing cask dependencies.",
|
||||
}],
|
||||
[:switch, "--zap", {
|
||||
description: "For use with `brew reinstall --cask`. Remove all files associated with a cask. " \
|
||||
"*May remove files which are shared between applications.*",
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--formula", args.last
|
||||
end
|
||||
cask_options
|
||||
Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the
|
||||
reinstalled formulae or, every 30 days, for all formulae.
|
||||
EOS
|
||||
switch "-d", "--debug",
|
||||
description: "If brewing fails, open an interactive debugging session with access to IRB " \
|
||||
"or a shell inside the temporary build directory."
|
||||
switch "-f", "--force",
|
||||
description: "Install without checking for previously installed keg-only or " \
|
||||
"non-migrated versions."
|
||||
switch "-v", "--verbose",
|
||||
description: "Print the verification and post-install steps."
|
||||
[
|
||||
[:switch, "--formula", "--formulae", { description: "Treat all named arguments as formulae." }],
|
||||
[:switch, "-s", "--build-from-source", {
|
||||
description: "Compile <formula> from source even if a bottle is available.",
|
||||
}],
|
||||
[:switch, "-i", "--interactive", {
|
||||
description: "Download and patch <formula>, then open a shell. This allows the user to " \
|
||||
"run `./configure --help` and otherwise determine how to turn the software " \
|
||||
"package into a Homebrew package.",
|
||||
}],
|
||||
[:switch, "--force-bottle", {
|
||||
description: "Install from a bottle if it exists for the current or newest version of " \
|
||||
"macOS, even if it would not normally be used for installation.",
|
||||
}],
|
||||
[:switch, "--keep-tmp", {
|
||||
description: "Retain the temporary files created during installation.",
|
||||
}],
|
||||
[:switch, "--debug-symbols", {
|
||||
depends_on: "--build-from-source",
|
||||
description: "Generate debug symbols on build. Source will be retained in a cache directory.",
|
||||
}],
|
||||
[:switch, "--display-times", {
|
||||
env: :display_install_times,
|
||||
description: "Print install times for each formula at the end of the run.",
|
||||
}],
|
||||
[:switch, "-g", "--git", {
|
||||
description: "Create a Git repository, useful for creating patches to the software.",
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--cask", args.last
|
||||
end
|
||||
formula_options
|
||||
[
|
||||
[:switch, "--cask", "--casks", { description: "Treat all named arguments as casks." }],
|
||||
[:switch, "--[no-]binaries", {
|
||||
description: "Disable/enable linking of helper executables (default: enabled).",
|
||||
env: :cask_opts_binaries,
|
||||
}],
|
||||
[:switch, "--require-sha", {
|
||||
description: "Require all casks to have a checksum.",
|
||||
env: :cask_opts_require_sha,
|
||||
}],
|
||||
[:switch, "--[no-]quarantine", {
|
||||
description: "Disable/enable quarantining of downloads (default: enabled).",
|
||||
env: :cask_opts_quarantine,
|
||||
}],
|
||||
[:switch, "--adopt", {
|
||||
description: "Adopt existing artifacts in the destination that are identical to those being installed. " \
|
||||
"Cannot be combined with `--force`.",
|
||||
}],
|
||||
[:switch, "--skip-cask-deps", {
|
||||
description: "Skip installing cask dependencies.",
|
||||
}],
|
||||
[:switch, "--zap", {
|
||||
description: "For use with `brew reinstall --cask`. Remove all files associated with a cask. " \
|
||||
"*May remove files which are shared between applications.*",
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--formula", args.last
|
||||
end
|
||||
cask_options
|
||||
|
||||
conflicts "--build-from-source", "--force-bottle"
|
||||
conflicts "--build-from-source", "--force-bottle"
|
||||
|
||||
named_args [:formula, :cask], min: 1
|
||||
end
|
||||
end
|
||||
|
||||
def self.reinstall
|
||||
args = reinstall_args.parse
|
||||
|
||||
formulae, casks = args.named.to_formulae_and_casks(method: :resolve)
|
||||
.partition { |o| o.is_a?(Formula) }
|
||||
|
||||
if args.build_from_source?
|
||||
unless DevelopmentTools.installed?
|
||||
raise BuildFlagsError.new(["--build-from-source"], bottled: formulae.all?(&:bottled?))
|
||||
named_args [:formula, :cask], min: 1
|
||||
end
|
||||
|
||||
unless Homebrew::EnvConfig.developer?
|
||||
opoo "building from source is not supported!"
|
||||
puts "You're on your own. Failures are expected so don't create any issues, please!"
|
||||
sig { override.void }
|
||||
def run
|
||||
formulae, casks = T.cast(
|
||||
args.named.to_formulae_and_casks(method: :resolve).partition { _1.is_a?(Formula) },
|
||||
[T::Array[Formula], T::Array[Cask::Cask]],
|
||||
)
|
||||
|
||||
if args.build_from_source?
|
||||
unless DevelopmentTools.installed?
|
||||
raise BuildFlagsError.new(["--build-from-source"], bottled: formulae.all?(&:bottled?))
|
||||
end
|
||||
|
||||
unless Homebrew::EnvConfig.developer?
|
||||
opoo "building from source is not supported!"
|
||||
puts "You're on your own. Failures are expected so don't create any issues, please!"
|
||||
end
|
||||
end
|
||||
|
||||
Install.perform_preinstall_checks
|
||||
|
||||
formulae.each do |formula|
|
||||
if formula.pinned?
|
||||
onoe "#{formula.full_name} is pinned. You must unpin it to reinstall."
|
||||
next
|
||||
end
|
||||
Migrator.migrate_if_needed(formula, force: args.force?)
|
||||
Homebrew.reinstall_formula(
|
||||
formula,
|
||||
flags: args.flags_only,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
git: args.git?,
|
||||
)
|
||||
Cleanup.install_formula_clean!(formula)
|
||||
end
|
||||
|
||||
Upgrade.check_installed_dependents(
|
||||
formulae,
|
||||
flags: args.flags_only,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
)
|
||||
|
||||
if casks.any?
|
||||
Cask::Reinstall.reinstall_casks(
|
||||
*casks,
|
||||
binaries: args.binaries?,
|
||||
verbose: args.verbose?,
|
||||
force: args.force?,
|
||||
require_sha: args.require_sha?,
|
||||
skip_cask_deps: args.skip_cask_deps?,
|
||||
quarantine: args.quarantine?,
|
||||
zap: args.zap?,
|
||||
)
|
||||
end
|
||||
|
||||
Cleanup.periodic_clean!
|
||||
|
||||
Homebrew.messages.display_messages(display_times: args.display_times?)
|
||||
end
|
||||
end
|
||||
|
||||
Install.perform_preinstall_checks
|
||||
|
||||
formulae.each do |formula|
|
||||
if formula.pinned?
|
||||
onoe "#{formula.full_name} is pinned. You must unpin it to reinstall."
|
||||
next
|
||||
end
|
||||
Migrator.migrate_if_needed(formula, force: args.force?)
|
||||
reinstall_formula(
|
||||
formula,
|
||||
flags: args.flags_only,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
git: args.git?,
|
||||
)
|
||||
Cleanup.install_formula_clean!(formula)
|
||||
end
|
||||
|
||||
Upgrade.check_installed_dependents(
|
||||
formulae,
|
||||
flags: args.flags_only,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
)
|
||||
|
||||
if casks.any?
|
||||
Cask::Reinstall.reinstall_casks(
|
||||
*casks,
|
||||
binaries: args.binaries?,
|
||||
verbose: args.verbose?,
|
||||
force: args.force?,
|
||||
require_sha: args.require_sha?,
|
||||
skip_cask_deps: args.skip_cask_deps?,
|
||||
quarantine: args.quarantine?,
|
||||
zap: args.zap?,
|
||||
)
|
||||
end
|
||||
|
||||
Cleanup.periodic_clean!
|
||||
|
||||
Homebrew.messages.display_messages(display_times: args.display_times?)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,165 +1,165 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "missing_formula"
|
||||
require "descriptions"
|
||||
require "cli/parser"
|
||||
require "search"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class SearchCmd < AbstractCommand
|
||||
PACKAGE_MANAGERS = {
|
||||
repology: ->(query) { "https://repology.org/projects/?search=#{query}" },
|
||||
macports: ->(query) { "https://ports.macports.org/search/?q=#{query}" },
|
||||
fink: ->(query) { "https://pdb.finkproject.org/pdb/browse.php?summary=#{query}" },
|
||||
opensuse: ->(query) { "https://software.opensuse.org/search?q=#{query}" },
|
||||
fedora: ->(query) { "https://packages.fedoraproject.org/search?query=#{query}" },
|
||||
archlinux: ->(query) { "https://archlinux.org/packages/?q=#{query}" },
|
||||
debian: lambda { |query|
|
||||
"https://packages.debian.org/search?keywords=#{query}&searchon=names&suite=all§ion=all"
|
||||
},
|
||||
ubuntu: lambda { |query|
|
||||
"https://packages.ubuntu.com/search?keywords=#{query}&searchon=names&suite=all§ion=all"
|
||||
},
|
||||
}.freeze
|
||||
|
||||
PACKAGE_MANAGERS = {
|
||||
repology: ->(query) { "https://repology.org/projects/?search=#{query}" },
|
||||
macports: ->(query) { "https://ports.macports.org/search/?q=#{query}" },
|
||||
fink: ->(query) { "https://pdb.finkproject.org/pdb/browse.php?summary=#{query}" },
|
||||
opensuse: ->(query) { "https://software.opensuse.org/search?q=#{query}" },
|
||||
fedora: ->(query) { "https://packages.fedoraproject.org/search?query=#{query}" },
|
||||
archlinux: ->(query) { "https://archlinux.org/packages/?q=#{query}" },
|
||||
debian: lambda { |query|
|
||||
"https://packages.debian.org/search?keywords=#{query}&searchon=names&suite=all§ion=all"
|
||||
},
|
||||
ubuntu: lambda { |query|
|
||||
"https://packages.ubuntu.com/search?keywords=#{query}&searchon=names&suite=all§ion=all"
|
||||
},
|
||||
}.freeze
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Perform a substring search of cask tokens and formula names for <text>. If <text>
|
||||
is flanked by slashes, it is interpreted as a regular expression.
|
||||
EOS
|
||||
switch "--formula", "--formulae",
|
||||
description: "Search for formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Search for casks."
|
||||
switch "--desc",
|
||||
description: "Search for formulae with a description matching <text> and casks with " \
|
||||
"a name or description matching <text>."
|
||||
switch "--eval-all",
|
||||
depends_on: "--desc",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not, to search their " \
|
||||
"descriptions. Implied if `HOMEBREW_EVAL_ALL` is set."
|
||||
switch "--pull-request",
|
||||
description: "Search for GitHub pull requests containing <text>."
|
||||
switch "--open",
|
||||
depends_on: "--pull-request",
|
||||
description: "Search for only open GitHub pull requests."
|
||||
switch "--closed",
|
||||
depends_on: "--pull-request",
|
||||
description: "Search for only closed GitHub pull requests."
|
||||
package_manager_switches = PACKAGE_MANAGERS.keys.map { |name| "--#{name}" }
|
||||
package_manager_switches.each do |s|
|
||||
switch s,
|
||||
description: "Search for <text> in the given database."
|
||||
end
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def search_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Perform a substring search of cask tokens and formula names for <text>. If <text>
|
||||
is flanked by slashes, it is interpreted as a regular expression.
|
||||
EOS
|
||||
switch "--formula", "--formulae",
|
||||
description: "Search for formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Search for casks."
|
||||
switch "--desc",
|
||||
description: "Search for formulae with a description matching <text> and casks with " \
|
||||
"a name or description matching <text>."
|
||||
switch "--eval-all",
|
||||
depends_on: "--desc",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not, to search their " \
|
||||
"descriptions. Implied if `HOMEBREW_EVAL_ALL` is set."
|
||||
switch "--pull-request",
|
||||
description: "Search for GitHub pull requests containing <text>."
|
||||
switch "--open",
|
||||
depends_on: "--pull-request",
|
||||
description: "Search for only open GitHub pull requests."
|
||||
switch "--closed",
|
||||
depends_on: "--pull-request",
|
||||
description: "Search for only closed GitHub pull requests."
|
||||
package_manager_switches = PACKAGE_MANAGERS.keys.map { |name| "--#{name}" }
|
||||
package_manager_switches.each do |s|
|
||||
switch s,
|
||||
description: "Search for <text> in the given database."
|
||||
conflicts "--desc", "--pull-request"
|
||||
conflicts "--open", "--closed"
|
||||
conflicts(*package_manager_switches)
|
||||
|
||||
named_args :text_or_regex, min: 1
|
||||
end
|
||||
|
||||
conflicts "--desc", "--pull-request"
|
||||
conflicts "--open", "--closed"
|
||||
conflicts(*package_manager_switches)
|
||||
sig { override.void }
|
||||
def run
|
||||
return if search_package_manager
|
||||
|
||||
named_args :text_or_regex, min: 1
|
||||
end
|
||||
end
|
||||
query = args.named.join(" ")
|
||||
string_or_regex = Search.query_regexp(query)
|
||||
|
||||
def search
|
||||
args = search_args.parse
|
||||
if args.desc?
|
||||
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
|
||||
raise UsageError, "`brew search --desc` needs `--eval-all` passed or `HOMEBREW_EVAL_ALL` set!"
|
||||
end
|
||||
|
||||
return if search_package_manager(args)
|
||||
Search.search_descriptions(string_or_regex, args)
|
||||
elsif args.pull_request?
|
||||
search_pull_requests(query)
|
||||
else
|
||||
formulae, casks = Search.search_names(string_or_regex, args)
|
||||
print_results(formulae, casks, query)
|
||||
end
|
||||
|
||||
query = args.named.join(" ")
|
||||
string_or_regex = Search.query_regexp(query)
|
||||
puts "Use `brew desc` to list packages with a short description." if args.verbose?
|
||||
|
||||
if args.desc?
|
||||
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
|
||||
raise UsageError, "`brew search --desc` needs `--eval-all` passed or `HOMEBREW_EVAL_ALL` set!"
|
||||
print_regex_help
|
||||
end
|
||||
|
||||
Search.search_descriptions(string_or_regex, args)
|
||||
elsif args.pull_request?
|
||||
search_pull_requests(query, args)
|
||||
else
|
||||
formulae, casks = Search.search_names(string_or_regex, args)
|
||||
print_results(formulae, casks, query)
|
||||
end
|
||||
private
|
||||
|
||||
puts "Use `brew desc` to list packages with a short description." if args.verbose?
|
||||
def print_regex_help
|
||||
return unless $stdout.tty?
|
||||
|
||||
print_regex_help(args)
|
||||
end
|
||||
metacharacters = %w[\\ | ( ) [ ] { } ^ $ * + ?].freeze
|
||||
return unless metacharacters.any? do |char|
|
||||
args.named.any? do |arg|
|
||||
arg.include?(char) && !arg.start_with?("/")
|
||||
end
|
||||
end
|
||||
|
||||
def print_regex_help(args)
|
||||
return unless $stdout.tty?
|
||||
opoo <<~EOS
|
||||
Did you mean to perform a regular expression search?
|
||||
Surround your query with /slashes/ to search locally by regex.
|
||||
EOS
|
||||
end
|
||||
|
||||
metacharacters = %w[\\ | ( ) [ ] { } ^ $ * + ?].freeze
|
||||
return unless metacharacters.any? do |char|
|
||||
args.named.any? do |arg|
|
||||
arg.include?(char) && !arg.start_with?("/")
|
||||
def search_package_manager
|
||||
package_manager = PACKAGE_MANAGERS.find { |name,| args[:"#{name}?"] }
|
||||
return false if package_manager.nil?
|
||||
|
||||
_, url = package_manager
|
||||
exec_browser url.call(URI.encode_www_form_component(args.named.join(" ")))
|
||||
true
|
||||
end
|
||||
|
||||
def search_pull_requests(query)
|
||||
only = if args.open? && !args.closed?
|
||||
"open"
|
||||
elsif args.closed? && !args.open?
|
||||
"closed"
|
||||
end
|
||||
|
||||
GitHub.print_pull_requests_matching(query, only)
|
||||
end
|
||||
|
||||
def print_results(all_formulae, all_casks, query)
|
||||
count = all_formulae.size + all_casks.size
|
||||
|
||||
if all_formulae.any?
|
||||
if $stdout.tty?
|
||||
ohai "Formulae", Formatter.columns(all_formulae)
|
||||
else
|
||||
puts all_formulae
|
||||
end
|
||||
end
|
||||
puts if all_formulae.any? && all_casks.any?
|
||||
if all_casks.any?
|
||||
if $stdout.tty?
|
||||
ohai "Casks", Formatter.columns(all_casks)
|
||||
else
|
||||
puts all_casks
|
||||
end
|
||||
end
|
||||
|
||||
print_missing_formula_help(query, count.positive?) if all_casks.exclude?(query)
|
||||
|
||||
odie "No formulae or casks found for #{query.inspect}." if count.zero?
|
||||
end
|
||||
|
||||
def print_missing_formula_help(query, found_matches)
|
||||
return unless $stdout.tty?
|
||||
|
||||
reason = MissingFormula.reason(query, silent: true)
|
||||
return if reason.nil?
|
||||
|
||||
if found_matches
|
||||
puts
|
||||
puts "If you meant #{query.inspect} specifically:"
|
||||
end
|
||||
puts reason
|
||||
end
|
||||
end
|
||||
|
||||
opoo <<~EOS
|
||||
Did you mean to perform a regular expression search?
|
||||
Surround your query with /slashes/ to search locally by regex.
|
||||
EOS
|
||||
end
|
||||
|
||||
def search_package_manager(args)
|
||||
package_manager = PACKAGE_MANAGERS.find { |name,| args[:"#{name}?"] }
|
||||
return false if package_manager.nil?
|
||||
|
||||
_, url = package_manager
|
||||
exec_browser url.call(URI.encode_www_form_component(args.named.join(" ")))
|
||||
true
|
||||
end
|
||||
|
||||
def search_pull_requests(query, args)
|
||||
only = if args.open? && !args.closed?
|
||||
"open"
|
||||
elsif args.closed? && !args.open?
|
||||
"closed"
|
||||
end
|
||||
|
||||
GitHub.print_pull_requests_matching(query, only)
|
||||
end
|
||||
|
||||
def print_results(all_formulae, all_casks, query)
|
||||
count = all_formulae.size + all_casks.size
|
||||
|
||||
if all_formulae.any?
|
||||
if $stdout.tty?
|
||||
ohai "Formulae", Formatter.columns(all_formulae)
|
||||
else
|
||||
puts all_formulae
|
||||
end
|
||||
end
|
||||
puts if all_formulae.any? && all_casks.any?
|
||||
if all_casks.any?
|
||||
if $stdout.tty?
|
||||
ohai "Casks", Formatter.columns(all_casks)
|
||||
else
|
||||
puts all_casks
|
||||
end
|
||||
end
|
||||
|
||||
print_missing_formula_help(query, count.positive?) if all_casks.exclude?(query)
|
||||
|
||||
odie "No formulae or casks found for #{query.inspect}." if count.zero?
|
||||
end
|
||||
|
||||
def print_missing_formula_help(query, found_matches)
|
||||
return unless $stdout.tty?
|
||||
|
||||
reason = MissingFormula.reason(query, silent: true)
|
||||
return if reason.nil?
|
||||
|
||||
if found_matches
|
||||
puts
|
||||
puts "If you meant #{query.inspect} specifically:"
|
||||
end
|
||||
puts reason
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,88 +1,88 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class TapInfo < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Show detailed information about one or more <tap>s.
|
||||
If no <tap> names are provided, display brief statistics for all installed taps.
|
||||
EOS
|
||||
switch "--installed",
|
||||
description: "Show information on each installed tap."
|
||||
flag "--json",
|
||||
description: "Print a JSON representation of <tap>. Currently the default and only accepted " \
|
||||
"value for <version> is `v1`. See the docs for examples of using the JSON " \
|
||||
"output: <https://docs.brew.sh/Querying-Brew>"
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def tap_info_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Show detailed information about one or more <tap>s.
|
||||
If no <tap> names are provided, display brief statistics for all installed taps.
|
||||
EOS
|
||||
switch "--installed",
|
||||
description: "Show information on each installed tap."
|
||||
flag "--json",
|
||||
description: "Print a JSON representation of <tap>. Currently the default and only accepted " \
|
||||
"value for <version> is `v1`. See the docs for examples of using the JSON " \
|
||||
"output: <https://docs.brew.sh/Querying-Brew>"
|
||||
|
||||
named_args :tap
|
||||
end
|
||||
end
|
||||
|
||||
def tap_info
|
||||
args = tap_info_args.parse
|
||||
|
||||
taps = if args.installed?
|
||||
Tap
|
||||
else
|
||||
args.named.to_taps
|
||||
end
|
||||
|
||||
if args.json
|
||||
raise UsageError, "invalid JSON version: #{args.json}" unless ["v1", true].include? args.json
|
||||
|
||||
print_tap_json(taps.sort_by(&:to_s))
|
||||
else
|
||||
print_tap_info(taps.sort_by(&:to_s))
|
||||
end
|
||||
end
|
||||
|
||||
def print_tap_info(taps)
|
||||
if taps.none?
|
||||
tap_count = 0
|
||||
formula_count = 0
|
||||
command_count = 0
|
||||
private_count = 0
|
||||
Tap.installed.each do |tap|
|
||||
tap_count += 1
|
||||
formula_count += tap.formula_files.size
|
||||
command_count += tap.command_files.size
|
||||
private_count += 1 if tap.private?
|
||||
named_args :tap
|
||||
end
|
||||
info = Utils.pluralize("tap", tap_count, include_count: true)
|
||||
info += ", #{private_count} private"
|
||||
info += ", #{Utils.pluralize("formula", formula_count, plural: "e", include_count: true)}"
|
||||
info += ", #{Utils.pluralize("command", command_count, include_count: true)}"
|
||||
info += ", #{Tap::TAP_DIRECTORY.dup.abv}" if Tap::TAP_DIRECTORY.directory?
|
||||
puts info
|
||||
else
|
||||
info = ""
|
||||
taps.each_with_index do |tap, i|
|
||||
puts unless i.zero?
|
||||
info = "#{tap}: "
|
||||
if tap.installed?
|
||||
info += if (contents = tap.contents).blank?
|
||||
"no commands/casks/formulae"
|
||||
else
|
||||
contents.join(", ")
|
||||
end
|
||||
info += ", private" if tap.private?
|
||||
info += "\n#{tap.path} (#{tap.path.abv})"
|
||||
info += "\nFrom: #{tap.remote.presence || "N/A"}"
|
||||
|
||||
sig { override.void }
|
||||
def run
|
||||
taps = if args.installed?
|
||||
Tap
|
||||
else
|
||||
info += "Not installed"
|
||||
args.named.to_taps
|
||||
end
|
||||
puts info
|
||||
|
||||
if args.json
|
||||
raise UsageError, "invalid JSON version: #{args.json}" unless ["v1", true].include? args.json
|
||||
|
||||
print_tap_json(taps.sort_by(&:to_s))
|
||||
else
|
||||
print_tap_info(taps.sort_by(&:to_s))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def print_tap_info(taps)
|
||||
if taps.none?
|
||||
tap_count = 0
|
||||
formula_count = 0
|
||||
command_count = 0
|
||||
private_count = 0
|
||||
Tap.installed.each do |tap|
|
||||
tap_count += 1
|
||||
formula_count += tap.formula_files.size
|
||||
command_count += tap.command_files.size
|
||||
private_count += 1 if tap.private?
|
||||
end
|
||||
info = Utils.pluralize("tap", tap_count, include_count: true)
|
||||
info += ", #{private_count} private"
|
||||
info += ", #{Utils.pluralize("formula", formula_count, plural: "e", include_count: true)}"
|
||||
info += ", #{Utils.pluralize("command", command_count, include_count: true)}"
|
||||
info += ", #{Tap::TAP_DIRECTORY.dup.abv}" if Tap::TAP_DIRECTORY.directory?
|
||||
puts info
|
||||
else
|
||||
info = ""
|
||||
taps.each_with_index do |tap, i|
|
||||
puts unless i.zero?
|
||||
info = "#{tap}: "
|
||||
if tap.installed?
|
||||
info += if (contents = tap.contents).blank?
|
||||
"no commands/casks/formulae"
|
||||
else
|
||||
contents.join(", ")
|
||||
end
|
||||
info += ", private" if tap.private?
|
||||
info += "\n#{tap.path} (#{tap.path.abv})"
|
||||
info += "\nFrom: #{tap.remote.presence || "N/A"}"
|
||||
else
|
||||
info += "Not installed"
|
||||
end
|
||||
puts info
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def print_tap_json(taps)
|
||||
puts JSON.pretty_generate(taps.map(&:to_hash))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def print_tap_json(taps)
|
||||
puts JSON.pretty_generate(taps.map(&:to_hash))
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,77 +1,75 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class TapCmd < AbstractCommand
|
||||
cmd_args do
|
||||
usage_banner "`tap` [<options>] [<user>`/`<repo>] [<URL>]"
|
||||
description <<~EOS
|
||||
Tap a formula repository.
|
||||
If no arguments are provided, list all installed taps.
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def tap_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
usage_banner "`tap` [<options>] [<user>`/`<repo>] [<URL>]"
|
||||
description <<~EOS
|
||||
Tap a formula repository.
|
||||
If no arguments are provided, list all installed taps.
|
||||
With <URL> unspecified, tap a formula repository from GitHub using HTTPS.
|
||||
Since so many taps are hosted on GitHub, this command is a shortcut for
|
||||
`brew tap` <user>`/`<repo> `https://github.com/`<user>`/homebrew-`<repo>.
|
||||
|
||||
With <URL> unspecified, tap a formula repository from GitHub using HTTPS.
|
||||
Since so many taps are hosted on GitHub, this command is a shortcut for
|
||||
`brew tap` <user>`/`<repo> `https://github.com/`<user>`/homebrew-`<repo>.
|
||||
With <URL> specified, tap a formula repository from anywhere, using
|
||||
any transport protocol that `git`(1) handles. The one-argument form of `tap`
|
||||
simplifies but also limits. This two-argument command makes no
|
||||
assumptions, so taps can be cloned from places other than GitHub and
|
||||
using protocols other than HTTPS, e.g. SSH, git, HTTP, FTP(S), rsync.
|
||||
EOS
|
||||
switch "--full",
|
||||
description: "Convert a shallow clone to a full clone without untapping. Taps are only cloned as " \
|
||||
"shallow clones if `--shallow` was originally passed.",
|
||||
replacement: false,
|
||||
disable: true
|
||||
switch "--shallow",
|
||||
description: "Fetch tap as a shallow clone rather than a full clone. Useful for continuous " \
|
||||
"integration.",
|
||||
replacement: false,
|
||||
disable: true
|
||||
switch "--[no-]force-auto-update",
|
||||
hidden: true
|
||||
switch "--custom-remote",
|
||||
description: "Install or change a tap with a custom remote. Useful for mirrors."
|
||||
switch "--repair",
|
||||
description: "Migrate tapped formulae from symlink-based to directory-based structure."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all the formulae, casks and aliases in the new tap to check validity. " \
|
||||
"Implied if `HOMEBREW_EVAL_ALL` is set."
|
||||
switch "--force",
|
||||
description: "Force install core taps even under API mode."
|
||||
|
||||
With <URL> specified, tap a formula repository from anywhere, using
|
||||
any transport protocol that `git`(1) handles. The one-argument form of `tap`
|
||||
simplifies but also limits. This two-argument command makes no
|
||||
assumptions, so taps can be cloned from places other than GitHub and
|
||||
using protocols other than HTTPS, e.g. SSH, git, HTTP, FTP(S), rsync.
|
||||
EOS
|
||||
switch "--full",
|
||||
description: "Convert a shallow clone to a full clone without untapping. Taps are only cloned as " \
|
||||
"shallow clones if `--shallow` was originally passed.",
|
||||
replacement: false,
|
||||
disable: true
|
||||
switch "--shallow",
|
||||
description: "Fetch tap as a shallow clone rather than a full clone. Useful for continuous integration.",
|
||||
replacement: false,
|
||||
disable: true
|
||||
switch "--[no-]force-auto-update",
|
||||
hidden: true
|
||||
switch "--custom-remote",
|
||||
description: "Install or change a tap with a custom remote. Useful for mirrors."
|
||||
switch "--repair",
|
||||
description: "Migrate tapped formulae from symlink-based to directory-based structure."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all the formulae, casks and aliases in the new tap to check validity. " \
|
||||
"Implied if `HOMEBREW_EVAL_ALL` is set."
|
||||
switch "--force",
|
||||
description: "Force install core taps even under API mode."
|
||||
|
||||
named_args :tap, max: 2
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def tap
|
||||
args = tap_args.parse
|
||||
|
||||
if args.repair?
|
||||
Tap.installed.each do |tap|
|
||||
tap.link_completions_and_manpages
|
||||
tap.fix_remote_configuration
|
||||
named_args :tap, max: 2
|
||||
end
|
||||
elsif args.no_named?
|
||||
puts Tap.installed.sort_by(&:name)
|
||||
else
|
||||
tap = Tap.fetch(args.named.first)
|
||||
begin
|
||||
tap.install clone_target: args.named.second,
|
||||
custom_remote: args.custom_remote?,
|
||||
quiet: args.quiet?,
|
||||
verify: args.eval_all? || Homebrew::EnvConfig.eval_all?,
|
||||
force: args.force?
|
||||
rescue TapRemoteMismatchError, TapNoCustomRemoteError => e
|
||||
odie e
|
||||
rescue TapAlreadyTappedError
|
||||
nil
|
||||
|
||||
sig { override.void }
|
||||
def run
|
||||
if args.repair?
|
||||
Tap.installed.each do |tap|
|
||||
tap.link_completions_and_manpages
|
||||
tap.fix_remote_configuration
|
||||
end
|
||||
elsif args.no_named?
|
||||
puts Tap.installed.sort_by(&:name)
|
||||
else
|
||||
tap = Tap.fetch(args.named.first)
|
||||
begin
|
||||
tap.install clone_target: args.named.second,
|
||||
custom_remote: args.custom_remote?,
|
||||
quiet: args.quiet?,
|
||||
verify: args.eval_all? || Homebrew::EnvConfig.eval_all?,
|
||||
force: args.force?
|
||||
rescue TapRemoteMismatchError, TapNoCustomRemoteError => e
|
||||
odie e
|
||||
rescue TapAlreadyTappedError
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "keg"
|
||||
require "formula"
|
||||
require "diagnostic"
|
||||
require "migrator"
|
||||
require "cli/parser"
|
||||
require "cask/cask_loader"
|
||||
require "cask/exceptions"
|
||||
require "cask/installer"
|
||||
@ -13,74 +13,72 @@ require "cask/uninstall"
|
||||
require "uninstall"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class UninstallCmd < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Uninstall a <formula> or <cask>.
|
||||
EOS
|
||||
switch "-f", "--force",
|
||||
description: "Delete all installed versions of <formula>. Uninstall even if <cask> is not " \
|
||||
"installed, overwrite existing files and ignore errors when removing files."
|
||||
switch "--zap",
|
||||
description: "Remove all files associated with a <cask>. " \
|
||||
"*May remove files which are shared between applications.*"
|
||||
switch "--ignore-dependencies",
|
||||
description: "Don't fail uninstall, even if <formula> is a dependency of any installed " \
|
||||
"formulae."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Treat all named arguments as formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Treat all named arguments as casks."
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def uninstall_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Uninstall a <formula> or <cask>.
|
||||
EOS
|
||||
switch "-f", "--force",
|
||||
description: "Delete all installed versions of <formula>. Uninstall even if <cask> is not " \
|
||||
"installed, overwrite existing files and ignore errors when removing files."
|
||||
switch "--zap",
|
||||
description: "Remove all files associated with a <cask>. " \
|
||||
"*May remove files which are shared between applications.*"
|
||||
switch "--ignore-dependencies",
|
||||
description: "Don't fail uninstall, even if <formula> is a dependency of any installed " \
|
||||
"formulae."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Treat all named arguments as formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Treat all named arguments as casks."
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--formula", "--zap"
|
||||
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--formula", "--zap"
|
||||
|
||||
named_args [:installed_formula, :installed_cask], min: 1
|
||||
end
|
||||
end
|
||||
|
||||
def uninstall
|
||||
args = uninstall_args.parse
|
||||
|
||||
all_kegs, casks = args.named.to_kegs_to_casks(
|
||||
ignore_unavailable: args.force?,
|
||||
all_kegs: args.force?,
|
||||
)
|
||||
|
||||
# If ignore_unavailable is true and the named args
|
||||
# are a series of invalid kegs and casks,
|
||||
# #to_kegs_to_casks will return empty arrays.
|
||||
return if all_kegs.blank? && casks.blank?
|
||||
|
||||
kegs_by_rack = all_kegs.group_by(&:rack)
|
||||
|
||||
Uninstall.uninstall_kegs(
|
||||
kegs_by_rack,
|
||||
casks:,
|
||||
force: args.force?,
|
||||
ignore_dependencies: args.ignore_dependencies?,
|
||||
named_args: args.named,
|
||||
)
|
||||
|
||||
if args.zap?
|
||||
casks.each do |cask|
|
||||
odebug "Zapping Cask #{cask}"
|
||||
|
||||
raise Cask::CaskNotInstalledError, cask if !cask.installed? && !args.force?
|
||||
|
||||
Cask::Installer.new(cask, verbose: args.verbose?, force: args.force?).zap
|
||||
named_args [:installed_formula, :installed_cask], min: 1
|
||||
end
|
||||
else
|
||||
Cask::Uninstall.uninstall_casks(
|
||||
*casks,
|
||||
verbose: args.verbose?,
|
||||
force: args.force?,
|
||||
)
|
||||
end
|
||||
|
||||
Cleanup.autoremove if Homebrew::EnvConfig.autoremove?
|
||||
sig { override.void }
|
||||
def run
|
||||
all_kegs, casks = args.named.to_kegs_to_casks(
|
||||
ignore_unavailable: args.force?,
|
||||
all_kegs: args.force?,
|
||||
)
|
||||
|
||||
# If ignore_unavailable is true and the named args
|
||||
# are a series of invalid kegs and casks,
|
||||
# #to_kegs_to_casks will return empty arrays.
|
||||
return if all_kegs.blank? && casks.blank?
|
||||
|
||||
kegs_by_rack = all_kegs.group_by(&:rack)
|
||||
|
||||
Uninstall.uninstall_kegs(
|
||||
kegs_by_rack,
|
||||
casks:,
|
||||
force: args.force?,
|
||||
ignore_dependencies: args.ignore_dependencies?,
|
||||
named_args: args.named,
|
||||
)
|
||||
|
||||
if args.zap?
|
||||
casks.each do |cask|
|
||||
odebug "Zapping Cask #{cask}"
|
||||
|
||||
raise Cask::CaskNotInstalledError, cask if !cask.installed? && !args.force?
|
||||
|
||||
Cask::Installer.new(cask, verbose: args.verbose?, force: args.force?).zap
|
||||
end
|
||||
else
|
||||
Cask::Uninstall.uninstall_casks(
|
||||
*casks,
|
||||
verbose: args.verbose?,
|
||||
force: args.force?,
|
||||
)
|
||||
end
|
||||
|
||||
Cleanup.autoremove if Homebrew::EnvConfig.autoremove?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,41 +1,39 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "unlink"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class UnlinkCmd < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Remove symlinks for <formula> from Homebrew's prefix. This can be useful
|
||||
for temporarily disabling a formula:
|
||||
`brew unlink` <formula> `&&` <commands> `&& brew link` <formula>
|
||||
EOS
|
||||
switch "-n", "--dry-run",
|
||||
description: "List files which would be unlinked without actually unlinking or " \
|
||||
"deleting any files."
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def unlink_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Remove symlinks for <formula> from Homebrew's prefix. This can be useful
|
||||
for temporarily disabling a formula:
|
||||
`brew unlink` <formula> `&&` <commands> `&& brew link` <formula>
|
||||
EOS
|
||||
switch "-n", "--dry-run",
|
||||
description: "List files which would be unlinked without actually unlinking or " \
|
||||
"deleting any files."
|
||||
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
end
|
||||
|
||||
def unlink
|
||||
args = unlink_args.parse
|
||||
|
||||
options = { dry_run: args.dry_run?, verbose: args.verbose? }
|
||||
|
||||
args.named.to_default_kegs.each do |keg|
|
||||
if args.dry_run?
|
||||
puts "Would remove:"
|
||||
keg.unlink(**options)
|
||||
next
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
|
||||
Unlink.unlink(keg, dry_run: args.dry_run?, verbose: args.verbose?)
|
||||
sig { override.void }
|
||||
def run
|
||||
options = { dry_run: args.dry_run?, verbose: args.verbose? }
|
||||
|
||||
args.named.to_default_kegs.each do |keg|
|
||||
if args.dry_run?
|
||||
puts "Would remove:"
|
||||
keg.unlink(**options)
|
||||
next
|
||||
end
|
||||
|
||||
Unlink.unlink(keg, dry_run: args.dry_run?, verbose: args.verbose?)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,34 +1,32 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "cli/parser"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class Unpin < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Unpin <formula>, allowing them to be upgraded by `brew upgrade` <formula>.
|
||||
See also `pin`.
|
||||
EOS
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def unpin_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Unpin <formula>, allowing them to be upgraded by `brew upgrade` <formula>.
|
||||
See also `pin`.
|
||||
EOS
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
|
||||
named_args :installed_formula, min: 1
|
||||
end
|
||||
end
|
||||
|
||||
def unpin
|
||||
args = unpin_args.parse
|
||||
|
||||
args.named.to_resolved_formulae.each do |f|
|
||||
if f.pinned?
|
||||
f.unpin
|
||||
elsif !f.pinnable?
|
||||
onoe "#{f.name} not installed"
|
||||
else
|
||||
opoo "#{f.name} not pinned"
|
||||
sig { override.void }
|
||||
def run
|
||||
args.named.to_resolved_formulae.each do |f|
|
||||
if f.pinned?
|
||||
f.unpin
|
||||
elsif !f.pinnable?
|
||||
onoe "#{f.name} not installed"
|
||||
else
|
||||
opoo "#{f.name} not pinned"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,51 +1,50 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "untap"
|
||||
|
||||
module Homebrew
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.untap_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Remove a tapped formula repository.
|
||||
EOS
|
||||
switch "-f", "--force",
|
||||
description: "Untap even if formulae or casks from this tap are currently installed."
|
||||
module Cmd
|
||||
class UntapCmd < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Remove a tapped formula repository.
|
||||
EOS
|
||||
switch "-f", "--force",
|
||||
description: "Untap even if formulae or casks from this tap are currently installed."
|
||||
|
||||
named_args :tap, min: 1
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def self.untap
|
||||
args = untap_args.parse
|
||||
|
||||
args.named.to_installed_taps.each do |tap|
|
||||
odie "Untapping #{tap} is not allowed" if tap.core_tap? && Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
if Homebrew::EnvConfig.no_install_from_api? || (!tap.core_tap? && !tap.core_cask_tap?)
|
||||
installed_tap_formulae = Untap.installed_formulae_for(tap:)
|
||||
installed_tap_casks = Untap.installed_casks_for(tap:)
|
||||
|
||||
if installed_tap_formulae.present? || installed_tap_casks.present?
|
||||
installed_names = (installed_tap_formulae + installed_tap_casks.map(&:token)).join("\n")
|
||||
if args.force? || Homebrew::EnvConfig.developer?
|
||||
opoo <<~EOS
|
||||
Untapping #{tap} even though it contains the following installed formulae or casks:
|
||||
#{installed_names}
|
||||
EOS
|
||||
else
|
||||
odie <<~EOS
|
||||
Refusing to untap #{tap} because it contains the following installed formulae or casks:
|
||||
#{installed_names}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
named_args :tap, min: 1
|
||||
end
|
||||
|
||||
tap.uninstall manual: true
|
||||
sig { override.void }
|
||||
def run
|
||||
args.named.to_installed_taps.each do |tap|
|
||||
odie "Untapping #{tap} is not allowed" if tap.core_tap? && Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
if Homebrew::EnvConfig.no_install_from_api? || (!tap.core_tap? && !tap.core_cask_tap?)
|
||||
installed_tap_formulae = Untap.installed_formulae_for(tap:)
|
||||
installed_tap_casks = Untap.installed_casks_for(tap:)
|
||||
|
||||
if installed_tap_formulae.present? || installed_tap_casks.present?
|
||||
installed_names = (installed_tap_formulae + installed_tap_casks.map(&:token)).join("\n")
|
||||
if args.force? || Homebrew::EnvConfig.developer?
|
||||
opoo <<~EOS
|
||||
Untapping #{tap} even though it contains the following installed formulae or casks:
|
||||
#{installed_names}
|
||||
EOS
|
||||
else
|
||||
odie <<~EOS
|
||||
Refusing to untap #{tap} because it contains the following installed formulae or casks:
|
||||
#{installed_names}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tap.uninstall manual: true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "migrator"
|
||||
require "formulary"
|
||||
require "cask/cask_loader"
|
||||
@ -8,405 +9,406 @@ require "cask/migrator"
|
||||
require "descriptions"
|
||||
require "cleanup"
|
||||
require "description_cache_store"
|
||||
require "cli/parser"
|
||||
require "settings"
|
||||
require "linuxbrew-core-migration"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
|
||||
def auto_update_header(args:)
|
||||
@auto_update_header ||= begin
|
||||
ohai "Auto-updated Homebrew!" if args.auto_update?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def update_report_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
The Ruby implementation of `brew update`. Never called manually.
|
||||
EOS
|
||||
switch "--auto-update", "--preinstall",
|
||||
description: "Run in 'auto-update' mode (faster, less output)."
|
||||
switch "-f", "--force",
|
||||
description: "Treat installed and updated formulae as if they are from " \
|
||||
"the same taps and migrate them anyway."
|
||||
|
||||
hide_from_man_page!
|
||||
end
|
||||
end
|
||||
|
||||
def update_report
|
||||
return output_update_report if $stdout.tty?
|
||||
|
||||
redirect_stdout($stderr) do
|
||||
output_update_report
|
||||
end
|
||||
end
|
||||
|
||||
def output_update_report
|
||||
args = update_report_args.parse
|
||||
|
||||
# Run `brew update` (again) if we've got a linuxbrew-core CoreTap
|
||||
if CoreTap.instance.installed? && CoreTap.instance.linuxbrew_core? &&
|
||||
ENV["HOMEBREW_LINUXBREW_CORE_MIGRATION"].blank?
|
||||
ohai "Re-running `brew update` for linuxbrew-core migration"
|
||||
|
||||
if Homebrew::EnvConfig.core_git_remote != HOMEBREW_CORE_DEFAULT_GIT_REMOTE
|
||||
opoo <<~EOS
|
||||
HOMEBREW_CORE_GIT_REMOTE was set: #{Homebrew::EnvConfig.core_git_remote}.
|
||||
It has been unset for the migration.
|
||||
You may need to change this from a linuxbrew-core mirror to a homebrew-core one.
|
||||
|
||||
module Cmd
|
||||
class UpdateReport < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
The Ruby implementation of `brew update`. Never called manually.
|
||||
EOS
|
||||
switch "--auto-update", "--preinstall",
|
||||
description: "Run in 'auto-update' mode (faster, less output)."
|
||||
switch "-f", "--force",
|
||||
description: "Treat installed and updated formulae as if they are from " \
|
||||
"the same taps and migrate them anyway."
|
||||
|
||||
hide_from_man_page!
|
||||
end
|
||||
ENV.delete("HOMEBREW_CORE_GIT_REMOTE")
|
||||
|
||||
if Homebrew::EnvConfig.bottle_domain != HOMEBREW_BOTTLE_DEFAULT_DOMAIN
|
||||
opoo <<~EOS
|
||||
HOMEBREW_BOTTLE_DOMAIN was set: #{Homebrew::EnvConfig.bottle_domain}.
|
||||
It has been unset for the migration.
|
||||
You may need to change this from a Linuxbrew package mirror to a Homebrew one.
|
||||
sig { override.void }
|
||||
def run
|
||||
return output_update_report if $stdout.tty?
|
||||
|
||||
EOS
|
||||
redirect_stdout($stderr) do
|
||||
output_update_report
|
||||
end
|
||||
end
|
||||
ENV.delete("HOMEBREW_BOTTLE_DOMAIN")
|
||||
|
||||
ENV["HOMEBREW_LINUXBREW_CORE_MIGRATION"] = "1"
|
||||
FileUtils.rm_f HOMEBREW_LOCKS/"update"
|
||||
private
|
||||
|
||||
update_args = []
|
||||
update_args << "--auto-update" if args.auto_update?
|
||||
update_args << "--force" if args.force?
|
||||
exec HOMEBREW_BREW_FILE, "update", *update_args
|
||||
end
|
||||
|
||||
if ENV["HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID"].present?
|
||||
opoo "HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID is now a no-op so can be unset."
|
||||
puts "All Homebrew Google Analytics code and data was destroyed."
|
||||
end
|
||||
|
||||
if ENV["HOMEBREW_NO_GOOGLE_ANALYTICS"].present?
|
||||
opoo "HOMEBREW_NO_GOOGLE_ANALYTICS is now a no-op so can be unset."
|
||||
puts "All Homebrew Google Analytics code and data was destroyed."
|
||||
end
|
||||
|
||||
unless args.quiet?
|
||||
analytics_message
|
||||
donation_message
|
||||
install_from_api_message
|
||||
end
|
||||
|
||||
tap_or_untap_core_taps_if_necessary
|
||||
|
||||
updated = false
|
||||
new_tag = nil
|
||||
|
||||
initial_revision = ENV["HOMEBREW_UPDATE_BEFORE"].to_s
|
||||
current_revision = ENV["HOMEBREW_UPDATE_AFTER"].to_s
|
||||
odie "update-report should not be called directly!" if initial_revision.empty? || current_revision.empty?
|
||||
|
||||
if initial_revision != current_revision
|
||||
auto_update_header(args:)
|
||||
|
||||
updated = true
|
||||
|
||||
old_tag = Settings.read "latesttag"
|
||||
|
||||
new_tag = Utils.popen_read(
|
||||
"git", "-C", HOMEBREW_REPOSITORY, "tag", "--list", "--sort=-version:refname", "*.*"
|
||||
).lines.first.chomp
|
||||
|
||||
Settings.write "latesttag", new_tag if new_tag != old_tag
|
||||
|
||||
if new_tag == old_tag
|
||||
ohai "Updated Homebrew from #{shorten_revision(initial_revision)} to #{shorten_revision(current_revision)}."
|
||||
elsif old_tag.blank?
|
||||
ohai "Updated Homebrew from #{shorten_revision(initial_revision)} " \
|
||||
"to #{new_tag} (#{shorten_revision(current_revision)})."
|
||||
else
|
||||
ohai "Updated Homebrew from #{old_tag} (#{shorten_revision(initial_revision)}) " \
|
||||
"to #{new_tag} (#{shorten_revision(current_revision)})."
|
||||
def auto_update_header
|
||||
@auto_update_header ||= begin
|
||||
ohai "Auto-updated Homebrew!" if args.auto_update?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Check if we can parse the JSON and do any Ruby-side follow-up.
|
||||
unless Homebrew::EnvConfig.no_install_from_api?
|
||||
Homebrew::API::Formula.write_names_and_aliases
|
||||
Homebrew::API::Cask.write_names
|
||||
end
|
||||
def output_update_report
|
||||
# Run `brew update` (again) if we've got a linuxbrew-core CoreTap
|
||||
if CoreTap.instance.installed? && CoreTap.instance.linuxbrew_core? &&
|
||||
ENV["HOMEBREW_LINUXBREW_CORE_MIGRATION"].blank?
|
||||
ohai "Re-running `brew update` for linuxbrew-core migration"
|
||||
|
||||
Homebrew.failed = true if ENV["HOMEBREW_UPDATE_FAILED"]
|
||||
return if Homebrew::EnvConfig.disable_load_formula?
|
||||
if Homebrew::EnvConfig.core_git_remote != HOMEBREW_CORE_DEFAULT_GIT_REMOTE
|
||||
opoo <<~EOS
|
||||
HOMEBREW_CORE_GIT_REMOTE was set: #{Homebrew::EnvConfig.core_git_remote}.
|
||||
It has been unset for the migration.
|
||||
You may need to change this from a linuxbrew-core mirror to a homebrew-core one.
|
||||
|
||||
migrate_gcc_dependents_if_needed
|
||||
|
||||
hub = ReporterHub.new
|
||||
|
||||
updated_taps = []
|
||||
Tap.installed.each do |tap|
|
||||
next if !tap.git? || tap.git_repo.origin_url.nil?
|
||||
next if (tap.core_tap? || tap.core_cask_tap?) && !Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
if ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"].present? && tap.core_tap? &&
|
||||
Settings.read("linuxbrewmigrated") != "true"
|
||||
ohai "Migrating formulae from linuxbrew-core to homebrew-core"
|
||||
|
||||
LINUXBREW_CORE_MIGRATION_LIST.each do |name|
|
||||
begin
|
||||
formula = Formula[name]
|
||||
rescue FormulaUnavailableError
|
||||
next
|
||||
EOS
|
||||
end
|
||||
next unless formula.any_version_installed?
|
||||
ENV.delete("HOMEBREW_CORE_GIT_REMOTE")
|
||||
|
||||
keg = formula.installed_kegs.last
|
||||
tab = Tab.for_keg(keg)
|
||||
# force a `brew upgrade` from the linuxbrew-core version to the homebrew-core version (even if lower)
|
||||
tab.source["versions"]["version_scheme"] = -1
|
||||
tab.write
|
||||
if Homebrew::EnvConfig.bottle_domain != HOMEBREW_BOTTLE_DEFAULT_DOMAIN
|
||||
opoo <<~EOS
|
||||
HOMEBREW_BOTTLE_DOMAIN was set: #{Homebrew::EnvConfig.bottle_domain}.
|
||||
It has been unset for the migration.
|
||||
You may need to change this from a Linuxbrew package mirror to a Homebrew one.
|
||||
|
||||
EOS
|
||||
end
|
||||
ENV.delete("HOMEBREW_BOTTLE_DOMAIN")
|
||||
|
||||
ENV["HOMEBREW_LINUXBREW_CORE_MIGRATION"] = "1"
|
||||
FileUtils.rm_f HOMEBREW_LOCKS/"update"
|
||||
|
||||
update_args = []
|
||||
update_args << "--auto-update" if args.auto_update?
|
||||
update_args << "--force" if args.force?
|
||||
exec HOMEBREW_BREW_FILE, "update", *update_args
|
||||
end
|
||||
|
||||
Settings.write "linuxbrewmigrated", true
|
||||
end
|
||||
if ENV["HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID"].present?
|
||||
opoo "HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID is now a no-op so can be unset."
|
||||
puts "All Homebrew Google Analytics code and data was destroyed."
|
||||
end
|
||||
|
||||
begin
|
||||
reporter = Reporter.new(tap)
|
||||
rescue Reporter::ReporterRevisionUnsetError => e
|
||||
onoe "#{e.message}\n#{Utils::Backtrace.clean(e)&.join("\n")}" if Homebrew::EnvConfig.developer?
|
||||
next
|
||||
end
|
||||
if reporter.updated?
|
||||
updated_taps << tap.name
|
||||
hub.add(reporter, auto_update: args.auto_update?)
|
||||
end
|
||||
end
|
||||
if ENV["HOMEBREW_NO_GOOGLE_ANALYTICS"].present?
|
||||
opoo "HOMEBREW_NO_GOOGLE_ANALYTICS is now a no-op so can be unset."
|
||||
puts "All Homebrew Google Analytics code and data was destroyed."
|
||||
end
|
||||
|
||||
# If we're installing from the API: we cannot use Git to check for #
|
||||
# differences in packages so instead use {formula,cask}_names.txt to do so.
|
||||
# The first time this runs: we won't yet have a base state
|
||||
# ({formula,cask}_names.before.txt) to compare against so we don't output a
|
||||
# anything and just copy the files for next time.
|
||||
unless Homebrew::EnvConfig.no_install_from_api?
|
||||
api_cache = Homebrew::API::HOMEBREW_CACHE_API
|
||||
core_tap = CoreTap.instance
|
||||
cask_tap = CoreCaskTap.instance
|
||||
[
|
||||
[:formula, core_tap, core_tap.formula_dir],
|
||||
[:cask, cask_tap, cask_tap.cask_dir],
|
||||
].each do |type, tap, dir|
|
||||
names_txt = api_cache/"#{type}_names.txt"
|
||||
next unless names_txt.exist?
|
||||
unless args.quiet?
|
||||
analytics_message
|
||||
donation_message
|
||||
install_from_api_message
|
||||
end
|
||||
|
||||
names_before_txt = api_cache/"#{type}_names.before.txt"
|
||||
if names_before_txt.exist?
|
||||
reporter = Reporter.new(
|
||||
tap,
|
||||
api_names_txt: names_txt,
|
||||
api_names_before_txt: names_before_txt,
|
||||
api_dir_prefix: dir,
|
||||
)
|
||||
tap_or_untap_core_taps_if_necessary
|
||||
|
||||
updated = false
|
||||
new_tag = nil
|
||||
|
||||
initial_revision = ENV["HOMEBREW_UPDATE_BEFORE"].to_s
|
||||
current_revision = ENV["HOMEBREW_UPDATE_AFTER"].to_s
|
||||
odie "update-report should not be called directly!" if initial_revision.empty? || current_revision.empty?
|
||||
|
||||
if initial_revision != current_revision
|
||||
auto_update_header
|
||||
|
||||
updated = true
|
||||
|
||||
old_tag = Settings.read "latesttag"
|
||||
|
||||
new_tag = Utils.popen_read(
|
||||
"git", "-C", HOMEBREW_REPOSITORY, "tag", "--list", "--sort=-version:refname", "*.*"
|
||||
).lines.first.chomp
|
||||
|
||||
Settings.write "latesttag", new_tag if new_tag != old_tag
|
||||
|
||||
if new_tag == old_tag
|
||||
ohai "Updated Homebrew from #{shorten_revision(initial_revision)} " \
|
||||
"to #{shorten_revision(current_revision)}."
|
||||
elsif old_tag.blank?
|
||||
ohai "Updated Homebrew from #{shorten_revision(initial_revision)} " \
|
||||
"to #{new_tag} (#{shorten_revision(current_revision)})."
|
||||
else
|
||||
ohai "Updated Homebrew from #{old_tag} (#{shorten_revision(initial_revision)}) " \
|
||||
"to #{new_tag} (#{shorten_revision(current_revision)})."
|
||||
end
|
||||
end
|
||||
|
||||
# Check if we can parse the JSON and do any Ruby-side follow-up.
|
||||
unless Homebrew::EnvConfig.no_install_from_api?
|
||||
Homebrew::API::Formula.write_names_and_aliases
|
||||
Homebrew::API::Cask.write_names
|
||||
end
|
||||
|
||||
Homebrew.failed = true if ENV["HOMEBREW_UPDATE_FAILED"]
|
||||
return if Homebrew::EnvConfig.disable_load_formula?
|
||||
|
||||
migrate_gcc_dependents_if_needed
|
||||
|
||||
hub = ReporterHub.new
|
||||
|
||||
updated_taps = []
|
||||
Tap.installed.each do |tap|
|
||||
next if !tap.git? || tap.git_repo.origin_url.nil?
|
||||
next if (tap.core_tap? || tap.core_cask_tap?) && !Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
if ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"].present? && tap.core_tap? &&
|
||||
Settings.read("linuxbrewmigrated") != "true"
|
||||
ohai "Migrating formulae from linuxbrew-core to homebrew-core"
|
||||
|
||||
LINUXBREW_CORE_MIGRATION_LIST.each do |name|
|
||||
begin
|
||||
formula = Formula[name]
|
||||
rescue FormulaUnavailableError
|
||||
next
|
||||
end
|
||||
next unless formula.any_version_installed?
|
||||
|
||||
keg = formula.installed_kegs.last
|
||||
tab = Tab.for_keg(keg)
|
||||
# force a `brew upgrade` from the linuxbrew-core version to the homebrew-core version (even if lower)
|
||||
tab.source["versions"]["version_scheme"] = -1
|
||||
tab.write
|
||||
end
|
||||
|
||||
Settings.write "linuxbrewmigrated", true
|
||||
end
|
||||
|
||||
begin
|
||||
reporter = Reporter.new(tap)
|
||||
rescue Reporter::ReporterRevisionUnsetError => e
|
||||
onoe "#{e.message}\n#{Utils::Backtrace.clean(e)&.join("\n")}" if Homebrew::EnvConfig.developer?
|
||||
next
|
||||
end
|
||||
if reporter.updated?
|
||||
updated_taps << tap.name
|
||||
hub.add(reporter, auto_update: args.auto_update?)
|
||||
end
|
||||
else
|
||||
FileUtils.cp names_txt, names_before_txt
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unless updated_taps.empty?
|
||||
auto_update_header(args:)
|
||||
puts "Updated #{Utils.pluralize("tap", updated_taps.count, include_count: true)} (#{updated_taps.to_sentence})."
|
||||
updated = true
|
||||
end
|
||||
|
||||
if updated
|
||||
if hub.empty?
|
||||
puts no_changes_message unless args.quiet?
|
||||
else
|
||||
if ENV.fetch("HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED", false)
|
||||
opoo "HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED is now the default behaviour, " \
|
||||
"so you can unset it from your environment."
|
||||
end
|
||||
|
||||
hub.dump(auto_update: args.auto_update?) unless args.quiet?
|
||||
hub.reporters.each(&:migrate_tap_migration)
|
||||
hub.reporters.each(&:migrate_cask_rename)
|
||||
hub.reporters.each { |r| r.migrate_formula_rename(force: args.force?, verbose: args.verbose?) }
|
||||
# If we're installing from the API: we cannot use Git to check for #
|
||||
# differences in packages so instead use {formula,cask}_names.txt to do so.
|
||||
# The first time this runs: we won't yet have a base state
|
||||
# ({formula,cask}_names.before.txt) to compare against so we don't output a
|
||||
# anything and just copy the files for next time.
|
||||
unless Homebrew::EnvConfig.no_install_from_api?
|
||||
api_cache = Homebrew::API::HOMEBREW_CACHE_API
|
||||
core_tap = CoreTap.instance
|
||||
cask_tap = CoreCaskTap.instance
|
||||
[
|
||||
[:formula, core_tap, core_tap.formula_dir],
|
||||
[:cask, cask_tap, cask_tap.cask_dir],
|
||||
].each do |type, tap, dir|
|
||||
names_txt = api_cache/"#{type}_names.txt"
|
||||
next unless names_txt.exist?
|
||||
|
||||
CacheStoreDatabase.use(:descriptions) do |db|
|
||||
DescriptionCacheStore.new(db)
|
||||
.update_from_report!(hub)
|
||||
end
|
||||
CacheStoreDatabase.use(:cask_descriptions) do |db|
|
||||
CaskDescriptionCacheStore.new(db)
|
||||
.update_from_report!(hub)
|
||||
end
|
||||
end
|
||||
puts if args.auto_update?
|
||||
elsif !args.auto_update? && !ENV["HOMEBREW_UPDATE_FAILED"] && !ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"]
|
||||
puts "Already up-to-date." unless args.quiet?
|
||||
end
|
||||
|
||||
Commands.rebuild_commands_completion_list
|
||||
link_completions_manpages_and_docs
|
||||
Tap.installed.each(&:link_completions_and_manpages)
|
||||
|
||||
failed_fetch_dirs = ENV["HOMEBREW_MISSING_REMOTE_REF_DIRS"]&.split("\n")
|
||||
if failed_fetch_dirs.present?
|
||||
failed_fetch_taps = failed_fetch_dirs.map { |dir| Tap.from_path(dir) }
|
||||
|
||||
ofail <<~EOS
|
||||
Some taps failed to update!
|
||||
The following taps can not read their remote branches:
|
||||
#{failed_fetch_taps.join("\n ")}
|
||||
This is happening because the remote branch was renamed or deleted.
|
||||
Reset taps to point to the correct remote branches by running `brew tap --repair`
|
||||
EOS
|
||||
end
|
||||
|
||||
return if new_tag.blank? || new_tag == old_tag || args.quiet?
|
||||
|
||||
puts
|
||||
|
||||
new_major_version, new_minor_version, new_patch_version = new_tag.split(".").map(&:to_i)
|
||||
old_major_version, old_minor_version = (old_tag.split(".")[0, 2]).map(&:to_i) if old_tag.present?
|
||||
if old_tag.blank? || new_major_version > old_major_version || new_minor_version > old_minor_version
|
||||
puts <<~EOS
|
||||
The #{new_major_version}.#{new_minor_version}.0 release notes are available on the Homebrew Blog:
|
||||
#{Formatter.url("https://brew.sh/blog/#{new_major_version}.#{new_minor_version}.0")}
|
||||
EOS
|
||||
end
|
||||
|
||||
return if new_patch_version.zero?
|
||||
|
||||
puts <<~EOS
|
||||
The #{new_tag} changelog can be found at:
|
||||
#{Formatter.url("https://github.com/Homebrew/brew/releases/tag/#{new_tag}")}
|
||||
EOS
|
||||
end
|
||||
|
||||
def no_changes_message
|
||||
"No changes to formulae or casks."
|
||||
end
|
||||
|
||||
def shorten_revision(revision)
|
||||
Utils.popen_read("git", "-C", HOMEBREW_REPOSITORY, "rev-parse", "--short", revision).chomp
|
||||
end
|
||||
|
||||
def tap_or_untap_core_taps_if_necessary
|
||||
return if ENV["HOMEBREW_UPDATE_TEST"]
|
||||
|
||||
if Homebrew::EnvConfig.no_install_from_api?
|
||||
return if Homebrew::EnvConfig.automatically_set_no_install_from_api?
|
||||
|
||||
core_tap = CoreTap.instance
|
||||
return if core_tap.installed?
|
||||
|
||||
core_tap.ensure_installed!
|
||||
revision = CoreTap.instance.git_head
|
||||
ENV["HOMEBREW_UPDATE_BEFORE_HOMEBREW_HOMEBREW_CORE"] = revision
|
||||
ENV["HOMEBREW_UPDATE_AFTER_HOMEBREW_HOMEBREW_CORE"] = revision
|
||||
else
|
||||
return if Homebrew::EnvConfig.developer? || ENV["HOMEBREW_DEV_CMD_RUN"]
|
||||
return if ENV["HOMEBREW_GITHUB_HOSTED_RUNNER"] || ENV["GITHUB_ACTIONS_HOMEBREW_SELF_HOSTED"]
|
||||
return if (HOMEBREW_PREFIX/".homebrewdocker").exist?
|
||||
|
||||
tap_output_header_printed = T.let(false, T::Boolean)
|
||||
[CoreTap.instance, CoreCaskTap.instance].each do |tap|
|
||||
next unless tap.installed?
|
||||
|
||||
if tap.git_branch == "master" &&
|
||||
(Date.parse(T.must(tap.git_repo.last_commit_date)) <= Date.today.prev_month)
|
||||
ohai "#{tap.name} is old and unneeded, untapping to save space..."
|
||||
tap.uninstall
|
||||
else
|
||||
unless tap_output_header_printed
|
||||
puts "Installing from the API is now the default behaviour!"
|
||||
puts "You can save space and time by running:"
|
||||
tap_output_header_printed = true
|
||||
names_before_txt = api_cache/"#{type}_names.before.txt"
|
||||
if names_before_txt.exist?
|
||||
reporter = Reporter.new(
|
||||
tap,
|
||||
api_names_txt: names_txt,
|
||||
api_names_before_txt: names_before_txt,
|
||||
api_dir_prefix: dir,
|
||||
)
|
||||
if reporter.updated?
|
||||
updated_taps << tap.name
|
||||
hub.add(reporter, auto_update: args.auto_update?)
|
||||
end
|
||||
else
|
||||
FileUtils.cp names_txt, names_before_txt
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unless updated_taps.empty?
|
||||
auto_update_header
|
||||
puts "Updated #{Utils.pluralize("tap", updated_taps.count,
|
||||
include_count: true)} (#{updated_taps.to_sentence})."
|
||||
updated = true
|
||||
end
|
||||
|
||||
if updated
|
||||
if hub.empty?
|
||||
puts no_changes_message unless args.quiet?
|
||||
else
|
||||
if ENV.fetch("HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED", false)
|
||||
opoo "HOMEBREW_UPDATE_REPORT_ONLY_INSTALLED is now the default behaviour, " \
|
||||
"so you can unset it from your environment."
|
||||
end
|
||||
|
||||
hub.dump(auto_update: args.auto_update?) unless args.quiet?
|
||||
hub.reporters.each(&:migrate_tap_migration)
|
||||
hub.reporters.each(&:migrate_cask_rename)
|
||||
hub.reporters.each { |r| r.migrate_formula_rename(force: args.force?, verbose: args.verbose?) }
|
||||
|
||||
CacheStoreDatabase.use(:descriptions) do |db|
|
||||
DescriptionCacheStore.new(db)
|
||||
.update_from_report!(hub)
|
||||
end
|
||||
CacheStoreDatabase.use(:cask_descriptions) do |db|
|
||||
CaskDescriptionCacheStore.new(db)
|
||||
.update_from_report!(hub)
|
||||
end
|
||||
end
|
||||
puts if args.auto_update?
|
||||
elsif !args.auto_update? && !ENV["HOMEBREW_UPDATE_FAILED"] && !ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"]
|
||||
puts "Already up-to-date." unless args.quiet?
|
||||
end
|
||||
|
||||
Commands.rebuild_commands_completion_list
|
||||
link_completions_manpages_and_docs
|
||||
Tap.installed.each(&:link_completions_and_manpages)
|
||||
|
||||
failed_fetch_dirs = ENV["HOMEBREW_MISSING_REMOTE_REF_DIRS"]&.split("\n")
|
||||
if failed_fetch_dirs.present?
|
||||
failed_fetch_taps = failed_fetch_dirs.map { |dir| Tap.from_path(dir) }
|
||||
|
||||
ofail <<~EOS
|
||||
Some taps failed to update!
|
||||
The following taps can not read their remote branches:
|
||||
#{failed_fetch_taps.join("\n ")}
|
||||
This is happening because the remote branch was renamed or deleted.
|
||||
Reset taps to point to the correct remote branches by running `brew tap --repair`
|
||||
EOS
|
||||
end
|
||||
|
||||
return if new_tag.blank? || new_tag == old_tag || args.quiet?
|
||||
|
||||
puts
|
||||
|
||||
new_major_version, new_minor_version, new_patch_version = new_tag.split(".").map(&:to_i)
|
||||
old_major_version, old_minor_version = (old_tag.split(".")[0, 2]).map(&:to_i) if old_tag.present?
|
||||
if old_tag.blank? || new_major_version > old_major_version || new_minor_version > old_minor_version
|
||||
puts <<~EOS
|
||||
The #{new_major_version}.#{new_minor_version}.0 release notes are available on the Homebrew Blog:
|
||||
#{Formatter.url("https://brew.sh/blog/#{new_major_version}.#{new_minor_version}.0")}
|
||||
EOS
|
||||
end
|
||||
|
||||
return if new_patch_version.zero?
|
||||
|
||||
puts <<~EOS
|
||||
The #{new_tag} changelog can be found at:
|
||||
#{Formatter.url("https://github.com/Homebrew/brew/releases/tag/#{new_tag}")}
|
||||
EOS
|
||||
end
|
||||
|
||||
def no_changes_message
|
||||
"No changes to formulae or casks."
|
||||
end
|
||||
|
||||
def shorten_revision(revision)
|
||||
Utils.popen_read("git", "-C", HOMEBREW_REPOSITORY, "rev-parse", "--short", revision).chomp
|
||||
end
|
||||
|
||||
def tap_or_untap_core_taps_if_necessary
|
||||
return if ENV["HOMEBREW_UPDATE_TEST"]
|
||||
|
||||
if Homebrew::EnvConfig.no_install_from_api?
|
||||
return if Homebrew::EnvConfig.automatically_set_no_install_from_api?
|
||||
|
||||
core_tap = CoreTap.instance
|
||||
return if core_tap.installed?
|
||||
|
||||
core_tap.ensure_installed!
|
||||
revision = CoreTap.instance.git_head
|
||||
ENV["HOMEBREW_UPDATE_BEFORE_HOMEBREW_HOMEBREW_CORE"] = revision
|
||||
ENV["HOMEBREW_UPDATE_AFTER_HOMEBREW_HOMEBREW_CORE"] = revision
|
||||
else
|
||||
return if Homebrew::EnvConfig.developer? || ENV["HOMEBREW_DEV_CMD_RUN"]
|
||||
return if ENV["HOMEBREW_GITHUB_HOSTED_RUNNER"] || ENV["GITHUB_ACTIONS_HOMEBREW_SELF_HOSTED"]
|
||||
return if (HOMEBREW_PREFIX/".homebrewdocker").exist?
|
||||
|
||||
tap_output_header_printed = T.let(false, T::Boolean)
|
||||
[CoreTap.instance, CoreCaskTap.instance].each do |tap|
|
||||
next unless tap.installed?
|
||||
|
||||
if tap.git_branch == "master" &&
|
||||
(Date.parse(T.must(tap.git_repo.last_commit_date)) <= Date.today.prev_month)
|
||||
ohai "#{tap.name} is old and unneeded, untapping to save space..."
|
||||
tap.uninstall
|
||||
else
|
||||
unless tap_output_header_printed
|
||||
puts "Installing from the API is now the default behaviour!"
|
||||
puts "You can save space and time by running:"
|
||||
tap_output_header_printed = true
|
||||
end
|
||||
puts " brew untap #{tap.name}"
|
||||
end
|
||||
end
|
||||
puts " brew untap #{tap.name}"
|
||||
end
|
||||
end
|
||||
|
||||
def link_completions_manpages_and_docs(repository = HOMEBREW_REPOSITORY)
|
||||
command = "brew update"
|
||||
Utils::Link.link_completions(repository, command)
|
||||
Utils::Link.link_manpages(repository, command)
|
||||
Utils::Link.link_docs(repository, command)
|
||||
rescue => e
|
||||
ofail <<~EOS
|
||||
Failed to link all completions, docs and manpages:
|
||||
#{e}
|
||||
EOS
|
||||
end
|
||||
|
||||
def migrate_gcc_dependents_if_needed
|
||||
# do nothing
|
||||
end
|
||||
|
||||
def analytics_message
|
||||
return if Utils::Analytics.messages_displayed?
|
||||
return if Utils::Analytics.no_message_output?
|
||||
|
||||
if Utils::Analytics.disabled? && !Utils::Analytics.influx_message_displayed?
|
||||
ohai "Homebrew's analytics have entirely moved to our InfluxDB instance in the EU."
|
||||
puts "We gather less data than before and have destroyed all Google Analytics data:"
|
||||
puts " #{Formatter.url("https://docs.brew.sh/Analytics")}#{Tty.reset}"
|
||||
puts "Please reconsider re-enabling analytics to help our volunteer maintainers with:"
|
||||
puts " brew analytics on"
|
||||
elsif !Utils::Analytics.disabled?
|
||||
ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
|
||||
# Use the shell's audible bell.
|
||||
print "\a"
|
||||
|
||||
# Use an extra newline and bold to avoid this being missed.
|
||||
ohai "Homebrew collects anonymous analytics."
|
||||
puts <<~EOS
|
||||
#{Tty.bold}Read the analytics documentation (and how to opt-out) here:
|
||||
#{Formatter.url("https://docs.brew.sh/Analytics")}#{Tty.reset}
|
||||
No analytics have been recorded yet (nor will be during this `brew` run).
|
||||
|
||||
EOS
|
||||
end
|
||||
|
||||
# Consider the messages possibly missed if not a TTY.
|
||||
Utils::Analytics.messages_displayed! if $stdout.tty?
|
||||
end
|
||||
|
||||
def donation_message
|
||||
return if Settings.read("donationmessage") == "true"
|
||||
|
||||
ohai "Homebrew is run entirely by unpaid volunteers. Please consider donating:"
|
||||
puts " #{Formatter.url("https://github.com/Homebrew/brew#donations")}\n\n"
|
||||
|
||||
# Consider the message possibly missed if not a TTY.
|
||||
Settings.write "donationmessage", true if $stdout.tty?
|
||||
end
|
||||
|
||||
def install_from_api_message
|
||||
return if Settings.read("installfromapimessage") == "true"
|
||||
|
||||
no_install_from_api_set = Homebrew::EnvConfig.no_install_from_api? &&
|
||||
!Homebrew::EnvConfig.automatically_set_no_install_from_api?
|
||||
return unless no_install_from_api_set
|
||||
|
||||
ohai "You have HOMEBREW_NO_INSTALL_FROM_API set"
|
||||
puts "Homebrew >=4.1.0 is dramatically faster and less error-prone when installing"
|
||||
puts "from the JSON API. Please consider unsetting HOMEBREW_NO_INSTALL_FROM_API."
|
||||
puts "This message will only be printed once."
|
||||
puts "\n\n"
|
||||
|
||||
# Consider the message possibly missed if not a TTY.
|
||||
Settings.write "installfromapimessage", true if $stdout.tty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def link_completions_manpages_and_docs(repository = HOMEBREW_REPOSITORY)
|
||||
command = "brew update"
|
||||
Utils::Link.link_completions(repository, command)
|
||||
Utils::Link.link_manpages(repository, command)
|
||||
Utils::Link.link_docs(repository, command)
|
||||
rescue => e
|
||||
ofail <<~EOS
|
||||
Failed to link all completions, docs and manpages:
|
||||
#{e}
|
||||
EOS
|
||||
end
|
||||
|
||||
def migrate_gcc_dependents_if_needed
|
||||
# do nothing
|
||||
end
|
||||
|
||||
def analytics_message
|
||||
return if Utils::Analytics.messages_displayed?
|
||||
return if Utils::Analytics.no_message_output?
|
||||
|
||||
if Utils::Analytics.disabled? && !Utils::Analytics.influx_message_displayed?
|
||||
ohai "Homebrew's analytics have entirely moved to our InfluxDB instance in the EU."
|
||||
puts "We gather less data than before and have destroyed all Google Analytics data:"
|
||||
puts " #{Formatter.url("https://docs.brew.sh/Analytics")}#{Tty.reset}"
|
||||
puts "Please reconsider re-enabling analytics to help our volunteer maintainers with:"
|
||||
puts " brew analytics on"
|
||||
elsif !Utils::Analytics.disabled?
|
||||
ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
|
||||
# Use the shell's audible bell.
|
||||
print "\a"
|
||||
|
||||
# Use an extra newline and bold to avoid this being missed.
|
||||
ohai "Homebrew collects anonymous analytics."
|
||||
puts <<~EOS
|
||||
#{Tty.bold}Read the analytics documentation (and how to opt-out) here:
|
||||
#{Formatter.url("https://docs.brew.sh/Analytics")}#{Tty.reset}
|
||||
No analytics have been recorded yet (nor will be during this `brew` run).
|
||||
|
||||
EOS
|
||||
end
|
||||
|
||||
# Consider the messages possibly missed if not a TTY.
|
||||
Utils::Analytics.messages_displayed! if $stdout.tty?
|
||||
end
|
||||
|
||||
def donation_message
|
||||
return if Settings.read("donationmessage") == "true"
|
||||
|
||||
ohai "Homebrew is run entirely by unpaid volunteers. Please consider donating:"
|
||||
puts " #{Formatter.url("https://github.com/Homebrew/brew#donations")}\n\n"
|
||||
|
||||
# Consider the message possibly missed if not a TTY.
|
||||
Settings.write "donationmessage", true if $stdout.tty?
|
||||
end
|
||||
|
||||
def install_from_api_message
|
||||
return if Settings.read("installfromapimessage") == "true"
|
||||
|
||||
no_install_from_api_set = Homebrew::EnvConfig.no_install_from_api? &&
|
||||
!Homebrew::EnvConfig.automatically_set_no_install_from_api?
|
||||
return unless no_install_from_api_set
|
||||
|
||||
ohai "You have HOMEBREW_NO_INSTALL_FROM_API set"
|
||||
puts "Homebrew >=4.1.0 is dramatically faster and less error-prone when installing"
|
||||
puts "from the JSON API. Please consider unsetting HOMEBREW_NO_INSTALL_FROM_API."
|
||||
puts "This message will only be printed once."
|
||||
puts "\n\n"
|
||||
|
||||
# Consider the message possibly missed if not a TTY.
|
||||
Settings.write "installfromapimessage", true if $stdout.tty?
|
||||
end
|
||||
end
|
||||
|
||||
require "extend/os/cmd/update-report"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
require "abstract_command"
|
||||
require "formula_installer"
|
||||
require "install"
|
||||
require "upgrade"
|
||||
@ -11,268 +11,268 @@ require "cask/macos"
|
||||
require "api"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module Cmd
|
||||
class UpgradeCmd < AbstractCommand
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Upgrade outdated casks and outdated, unpinned formulae using the same options they were originally
|
||||
installed with, plus any appended brew formula options. If <cask> or <formula> are specified,
|
||||
upgrade only the given <cask> or <formula> kegs (unless they are pinned; see `pin`, `unpin`).
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def upgrade_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Upgrade outdated casks and outdated, unpinned formulae using the same options they were originally
|
||||
installed with, plus any appended brew formula options. If <cask> or <formula> are specified,
|
||||
upgrade only the given <cask> or <formula> kegs (unless they are pinned; see `pin`, `unpin`).
|
||||
Unless `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK` is set, `brew upgrade` or `brew reinstall` will be run for
|
||||
outdated dependents and dependents with broken linkage, respectively.
|
||||
|
||||
Unless `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK` is set, `brew upgrade` or `brew reinstall` will be run for
|
||||
outdated dependents and dependents with broken linkage, respectively.
|
||||
|
||||
Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the
|
||||
upgraded formulae or, every 30 days, for all formulae.
|
||||
EOS
|
||||
switch "-d", "--debug",
|
||||
description: "If brewing fails, open an interactive debugging session with access to IRB " \
|
||||
"or a shell inside the temporary build directory."
|
||||
switch "-f", "--force",
|
||||
description: "Install formulae without checking for previously installed keg-only or " \
|
||||
"non-migrated versions. When installing casks, overwrite existing files " \
|
||||
"(binaries and symlinks are excluded, unless originally from the same cask)."
|
||||
switch "-v", "--verbose",
|
||||
description: "Print the verification and post-install steps."
|
||||
switch "-n", "--dry-run",
|
||||
description: "Show what would be upgraded, but do not actually upgrade anything."
|
||||
[
|
||||
[:switch, "--formula", "--formulae", {
|
||||
description: "Treat all named arguments as formulae. If no named arguments " \
|
||||
"are specified, upgrade only outdated formulae.",
|
||||
}],
|
||||
[:switch, "-s", "--build-from-source", {
|
||||
description: "Compile <formula> from source even if a bottle is available.",
|
||||
}],
|
||||
[:switch, "-i", "--interactive", {
|
||||
description: "Download and patch <formula>, then open a shell. This allows the user to " \
|
||||
"run `./configure --help` and otherwise determine how to turn the software " \
|
||||
"package into a Homebrew package.",
|
||||
}],
|
||||
[:switch, "--force-bottle", {
|
||||
description: "Install from a bottle if it exists for the current or newest version of " \
|
||||
"macOS, even if it would not normally be used for installation.",
|
||||
}],
|
||||
[:switch, "--fetch-HEAD", {
|
||||
description: "Fetch the upstream repository to detect if the HEAD installation of the " \
|
||||
"formula is outdated. Otherwise, the repository's HEAD will only be checked for " \
|
||||
"updates when a new stable or development version has been released.",
|
||||
}],
|
||||
[:switch, "--ignore-pinned", {
|
||||
description: "Set a successful exit status even if pinned formulae are not upgraded.",
|
||||
hidden: true,
|
||||
}],
|
||||
[:switch, "--keep-tmp", {
|
||||
description: "Retain the temporary files created during installation.",
|
||||
}],
|
||||
[:switch, "--debug-symbols", {
|
||||
depends_on: "--build-from-source",
|
||||
description: "Generate debug symbols on build. Source will be retained in a cache directory.",
|
||||
}],
|
||||
[:switch, "--display-times", {
|
||||
env: :display_install_times,
|
||||
description: "Print install times for each package at the end of the run.",
|
||||
}],
|
||||
[:switch, "--overwrite", {
|
||||
description: "Delete files that already exist in the prefix while linking.",
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--cask", args.last
|
||||
end
|
||||
formula_options
|
||||
[
|
||||
[:switch, "--cask", "--casks", {
|
||||
description: "Treat all named arguments as casks. If no named arguments " \
|
||||
"are specified, upgrade only outdated casks.",
|
||||
}],
|
||||
[:switch, "--skip-cask-deps", {
|
||||
description: "Skip installing cask dependencies.",
|
||||
}],
|
||||
[:switch, "-g", "--greedy", {
|
||||
description: "Also include casks with `auto_updates true` or `version :latest`.",
|
||||
}],
|
||||
[:switch, "--greedy-latest", {
|
||||
description: "Also include casks with `version :latest`.",
|
||||
}],
|
||||
[:switch, "--greedy-auto-updates", {
|
||||
description: "Also include casks with `auto_updates true`.",
|
||||
}],
|
||||
[:switch, "--[no-]binaries", {
|
||||
description: "Disable/enable linking of helper executables (default: enabled).",
|
||||
env: :cask_opts_binaries,
|
||||
}],
|
||||
[:switch, "--require-sha", {
|
||||
description: "Require all casks to have a checksum.",
|
||||
env: :cask_opts_require_sha,
|
||||
}],
|
||||
[:switch, "--[no-]quarantine", {
|
||||
description: "Disable/enable quarantining of downloads (default: enabled).",
|
||||
env: :cask_opts_quarantine,
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--formula", args.last
|
||||
end
|
||||
cask_options
|
||||
|
||||
conflicts "--build-from-source", "--force-bottle"
|
||||
|
||||
named_args [:installed_formula, :installed_cask]
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def upgrade
|
||||
args = upgrade_args.parse
|
||||
|
||||
# Deprecated since this is now the default behavior.
|
||||
odeprecated "`brew upgrade --ignore-pinned`" if args.ignore_pinned?
|
||||
|
||||
formulae, casks = args.named.to_resolved_formulae_to_casks
|
||||
# If one or more formulae are specified, but no casks were
|
||||
# specified, we want to make note of that so we don't
|
||||
# try to upgrade all outdated casks.
|
||||
only_upgrade_formulae = formulae.present? && casks.blank?
|
||||
only_upgrade_casks = casks.present? && formulae.blank?
|
||||
|
||||
upgrade_outdated_formulae(formulae, args:) unless only_upgrade_casks
|
||||
upgrade_outdated_casks(casks, args:) unless only_upgrade_formulae
|
||||
|
||||
Cleanup.periodic_clean!(dry_run: args.dry_run?)
|
||||
|
||||
Homebrew.messages.display_messages(display_times: args.display_times?)
|
||||
end
|
||||
|
||||
sig { params(formulae: T::Array[Formula], args: T.untyped).returns(T::Boolean) }
|
||||
def upgrade_outdated_formulae(formulae, args:)
|
||||
return false if args.cask?
|
||||
|
||||
if args.build_from_source?
|
||||
unless DevelopmentTools.installed?
|
||||
raise BuildFlagsError.new(["--build-from-source"], bottled: formulae.all?(&:bottled?))
|
||||
end
|
||||
|
||||
unless Homebrew::EnvConfig.developer?
|
||||
opoo "building from source is not supported!"
|
||||
puts "You're on your own. Failures are expected so don't create any issues, please!"
|
||||
end
|
||||
end
|
||||
|
||||
Install.perform_preinstall_checks
|
||||
|
||||
if formulae.blank?
|
||||
outdated = Formula.installed.select do |f|
|
||||
f.outdated?(fetch_head: args.fetch_HEAD?)
|
||||
end
|
||||
else
|
||||
outdated, not_outdated = formulae.partition do |f|
|
||||
f.outdated?(fetch_head: args.fetch_HEAD?)
|
||||
end
|
||||
|
||||
not_outdated.each do |f|
|
||||
latest_keg = f.installed_kegs.max_by(&:scheme_and_version)
|
||||
if latest_keg.nil?
|
||||
ofail "#{f.full_specified_name} not installed"
|
||||
else
|
||||
opoo "#{f.full_specified_name} #{latest_keg.version} already installed"
|
||||
Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the
|
||||
upgraded formulae or, every 30 days, for all formulae.
|
||||
EOS
|
||||
switch "-d", "--debug",
|
||||
description: "If brewing fails, open an interactive debugging session with access to IRB " \
|
||||
"or a shell inside the temporary build directory."
|
||||
switch "-f", "--force",
|
||||
description: "Install formulae without checking for previously installed keg-only or " \
|
||||
"non-migrated versions. When installing casks, overwrite existing files " \
|
||||
"(binaries and symlinks are excluded, unless originally from the same cask)."
|
||||
switch "-v", "--verbose",
|
||||
description: "Print the verification and post-install steps."
|
||||
switch "-n", "--dry-run",
|
||||
description: "Show what would be upgraded, but do not actually upgrade anything."
|
||||
[
|
||||
[:switch, "--formula", "--formulae", {
|
||||
description: "Treat all named arguments as formulae. If no named arguments " \
|
||||
"are specified, upgrade only outdated formulae.",
|
||||
}],
|
||||
[:switch, "-s", "--build-from-source", {
|
||||
description: "Compile <formula> from source even if a bottle is available.",
|
||||
}],
|
||||
[:switch, "-i", "--interactive", {
|
||||
description: "Download and patch <formula>, then open a shell. This allows the user to " \
|
||||
"run `./configure --help` and otherwise determine how to turn the software " \
|
||||
"package into a Homebrew package.",
|
||||
}],
|
||||
[:switch, "--force-bottle", {
|
||||
description: "Install from a bottle if it exists for the current or newest version of " \
|
||||
"macOS, even if it would not normally be used for installation.",
|
||||
}],
|
||||
[:switch, "--fetch-HEAD", {
|
||||
description: "Fetch the upstream repository to detect if the HEAD installation of the " \
|
||||
"formula is outdated. Otherwise, the repository's HEAD will only be checked for " \
|
||||
"updates when a new stable or development version has been released.",
|
||||
}],
|
||||
[:switch, "--ignore-pinned", {
|
||||
description: "Set a successful exit status even if pinned formulae are not upgraded.",
|
||||
hidden: true,
|
||||
}],
|
||||
[:switch, "--keep-tmp", {
|
||||
description: "Retain the temporary files created during installation.",
|
||||
}],
|
||||
[:switch, "--debug-symbols", {
|
||||
depends_on: "--build-from-source",
|
||||
description: "Generate debug symbols on build. Source will be retained in a cache directory.",
|
||||
}],
|
||||
[:switch, "--display-times", {
|
||||
env: :display_install_times,
|
||||
description: "Print install times for each package at the end of the run.",
|
||||
}],
|
||||
[:switch, "--overwrite", {
|
||||
description: "Delete files that already exist in the prefix while linking.",
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--cask", args.last
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false if outdated.blank?
|
||||
|
||||
pinned = outdated.select(&:pinned?)
|
||||
outdated -= pinned
|
||||
formulae_to_install = outdated.map do |f|
|
||||
f_latest = f.latest_formula
|
||||
if f_latest.latest_version_installed?
|
||||
f
|
||||
else
|
||||
f_latest
|
||||
end
|
||||
end
|
||||
|
||||
if pinned.any?
|
||||
Kernel.public_send(
|
||||
formulae.any? ? :ofail : :opoo, # only fail when pinned formulae are named explicitly
|
||||
"Not upgrading #{pinned.count} pinned #{Utils.pluralize("package", pinned.count)}:",
|
||||
)
|
||||
puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
|
||||
end
|
||||
|
||||
if formulae_to_install.empty?
|
||||
oh1 "No packages to upgrade"
|
||||
else
|
||||
verb = args.dry_run? ? "Would upgrade" : "Upgrading"
|
||||
oh1 "#{verb} #{formulae_to_install.count} outdated #{Utils.pluralize("package", formulae_to_install.count)}:"
|
||||
formulae_upgrades = formulae_to_install.map do |f|
|
||||
if f.optlinked?
|
||||
"#{f.full_specified_name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
|
||||
else
|
||||
"#{f.full_specified_name} #{f.pkg_version}"
|
||||
formula_options
|
||||
[
|
||||
[:switch, "--cask", "--casks", {
|
||||
description: "Treat all named arguments as casks. If no named arguments " \
|
||||
"are specified, upgrade only outdated casks.",
|
||||
}],
|
||||
[:switch, "--skip-cask-deps", {
|
||||
description: "Skip installing cask dependencies.",
|
||||
}],
|
||||
[:switch, "-g", "--greedy", {
|
||||
description: "Also include casks with `auto_updates true` or `version :latest`.",
|
||||
}],
|
||||
[:switch, "--greedy-latest", {
|
||||
description: "Also include casks with `version :latest`.",
|
||||
}],
|
||||
[:switch, "--greedy-auto-updates", {
|
||||
description: "Also include casks with `auto_updates true`.",
|
||||
}],
|
||||
[:switch, "--[no-]binaries", {
|
||||
description: "Disable/enable linking of helper executables (default: enabled).",
|
||||
env: :cask_opts_binaries,
|
||||
}],
|
||||
[:switch, "--require-sha", {
|
||||
description: "Require all casks to have a checksum.",
|
||||
env: :cask_opts_require_sha,
|
||||
}],
|
||||
[:switch, "--[no-]quarantine", {
|
||||
description: "Disable/enable quarantining of downloads (default: enabled).",
|
||||
env: :cask_opts_quarantine,
|
||||
}],
|
||||
].each do |args|
|
||||
options = args.pop
|
||||
send(*args, **options)
|
||||
conflicts "--formula", args.last
|
||||
end
|
||||
cask_options
|
||||
|
||||
conflicts "--build-from-source", "--force-bottle"
|
||||
|
||||
named_args [:installed_formula, :installed_cask]
|
||||
end
|
||||
|
||||
sig { override.void }
|
||||
def run
|
||||
# Deprecated since this is now the default behavior.
|
||||
odeprecated "`brew upgrade --ignore-pinned`" if args.ignore_pinned?
|
||||
|
||||
formulae, casks = args.named.to_resolved_formulae_to_casks
|
||||
# If one or more formulae are specified, but no casks were
|
||||
# specified, we want to make note of that so we don't
|
||||
# try to upgrade all outdated casks.
|
||||
only_upgrade_formulae = formulae.present? && casks.blank?
|
||||
only_upgrade_casks = casks.present? && formulae.blank?
|
||||
|
||||
upgrade_outdated_formulae(formulae) unless only_upgrade_casks
|
||||
upgrade_outdated_casks(casks) unless only_upgrade_formulae
|
||||
|
||||
Cleanup.periodic_clean!(dry_run: args.dry_run?)
|
||||
|
||||
Homebrew.messages.display_messages(display_times: args.display_times?)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { params(formulae: T::Array[Formula]).returns(T::Boolean) }
|
||||
def upgrade_outdated_formulae(formulae)
|
||||
return false if args.cask?
|
||||
|
||||
if args.build_from_source?
|
||||
unless DevelopmentTools.installed?
|
||||
raise BuildFlagsError.new(["--build-from-source"], bottled: formulae.all?(&:bottled?))
|
||||
end
|
||||
|
||||
unless Homebrew::EnvConfig.developer?
|
||||
opoo "building from source is not supported!"
|
||||
puts "You're on your own. Failures are expected so don't create any issues, please!"
|
||||
end
|
||||
end
|
||||
|
||||
Install.perform_preinstall_checks
|
||||
|
||||
if formulae.blank?
|
||||
outdated = Formula.installed.select do |f|
|
||||
f.outdated?(fetch_head: args.fetch_HEAD?)
|
||||
end
|
||||
else
|
||||
outdated, not_outdated = formulae.partition do |f|
|
||||
f.outdated?(fetch_head: args.fetch_HEAD?)
|
||||
end
|
||||
|
||||
not_outdated.each do |f|
|
||||
latest_keg = f.installed_kegs.max_by(&:scheme_and_version)
|
||||
if latest_keg.nil?
|
||||
ofail "#{f.full_specified_name} not installed"
|
||||
else
|
||||
opoo "#{f.full_specified_name} #{latest_keg.version} already installed"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false if outdated.blank?
|
||||
|
||||
pinned = outdated.select(&:pinned?)
|
||||
outdated -= pinned
|
||||
formulae_to_install = outdated.map do |f|
|
||||
f_latest = f.latest_formula
|
||||
if f_latest.latest_version_installed?
|
||||
f
|
||||
else
|
||||
f_latest
|
||||
end
|
||||
end
|
||||
|
||||
if pinned.any?
|
||||
Kernel.public_send(
|
||||
formulae.any? ? :ofail : :opoo, # only fail when pinned formulae are named explicitly
|
||||
"Not upgrading #{pinned.count} pinned #{Utils.pluralize("package", pinned.count)}:",
|
||||
)
|
||||
puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
|
||||
end
|
||||
|
||||
if formulae_to_install.empty?
|
||||
oh1 "No packages to upgrade"
|
||||
else
|
||||
verb = args.dry_run? ? "Would upgrade" : "Upgrading"
|
||||
oh1 "#{verb} #{formulae_to_install.count} outdated #{Utils.pluralize("package",
|
||||
formulae_to_install.count)}:"
|
||||
formulae_upgrades = formulae_to_install.map do |f|
|
||||
if f.optlinked?
|
||||
"#{f.full_specified_name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
|
||||
else
|
||||
"#{f.full_specified_name} #{f.pkg_version}"
|
||||
end
|
||||
end
|
||||
puts formulae_upgrades.join("\n")
|
||||
end
|
||||
|
||||
Upgrade.upgrade_formulae(
|
||||
formulae_to_install,
|
||||
flags: args.flags_only,
|
||||
dry_run: args.dry_run?,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
overwrite: args.overwrite?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
)
|
||||
|
||||
Upgrade.check_installed_dependents(
|
||||
formulae_to_install,
|
||||
flags: args.flags_only,
|
||||
dry_run: args.dry_run?,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
sig { params(casks: T::Array[Cask::Cask]).returns(T::Boolean) }
|
||||
def upgrade_outdated_casks(casks)
|
||||
return false if args.formula?
|
||||
|
||||
Cask::Upgrade.upgrade_casks(
|
||||
*casks,
|
||||
force: args.force?,
|
||||
greedy: args.greedy?,
|
||||
greedy_latest: args.greedy_latest?,
|
||||
greedy_auto_updates: args.greedy_auto_updates?,
|
||||
dry_run: args.dry_run?,
|
||||
binaries: args.binaries?,
|
||||
quarantine: args.quarantine?,
|
||||
require_sha: args.require_sha?,
|
||||
skip_cask_deps: args.skip_cask_deps?,
|
||||
verbose: args.verbose?,
|
||||
args:,
|
||||
)
|
||||
end
|
||||
puts formulae_upgrades.join("\n")
|
||||
end
|
||||
|
||||
Upgrade.upgrade_formulae(
|
||||
formulae_to_install,
|
||||
flags: args.flags_only,
|
||||
dry_run: args.dry_run?,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
overwrite: args.overwrite?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
)
|
||||
|
||||
Upgrade.check_installed_dependents(
|
||||
formulae_to_install,
|
||||
flags: args.flags_only,
|
||||
dry_run: args.dry_run?,
|
||||
installed_on_request: args.named.present?,
|
||||
force_bottle: args.force_bottle?,
|
||||
build_from_source_formulae: args.build_from_source_formulae,
|
||||
interactive: args.interactive?,
|
||||
keep_tmp: args.keep_tmp?,
|
||||
debug_symbols: args.debug_symbols?,
|
||||
force: args.force?,
|
||||
debug: args.debug?,
|
||||
quiet: args.quiet?,
|
||||
verbose: args.verbose?,
|
||||
)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
sig { params(casks: T::Array[Cask::Cask], args: T.untyped).returns(T::Boolean) }
|
||||
def upgrade_outdated_casks(casks, args:)
|
||||
return false if args.formula?
|
||||
|
||||
Cask::Upgrade.upgrade_casks(
|
||||
*casks,
|
||||
force: args.force?,
|
||||
greedy: args.greedy?,
|
||||
greedy_latest: args.greedy_latest?,
|
||||
greedy_auto_updates: args.greedy_auto_updates?,
|
||||
dry_run: args.dry_run?,
|
||||
binaries: args.binaries?,
|
||||
quarantine: args.quarantine?,
|
||||
require_sha: args.require_sha?,
|
||||
skip_cask_deps: args.skip_cask_deps?,
|
||||
verbose: args.verbose?,
|
||||
args:,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,166 +1,167 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
# `brew uses foo bar` returns formulae that use both foo and bar
|
||||
# If you want the union, run the command twice and concatenate the results.
|
||||
# The intersection is harder to achieve with shell tools.
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "cli/parser"
|
||||
require "cask/caskroom"
|
||||
require "dependencies_helpers"
|
||||
require "ostruct"
|
||||
|
||||
module Homebrew
|
||||
extend DependenciesHelpers
|
||||
module Cmd
|
||||
# `brew uses foo bar` returns formulae that use both foo and bar
|
||||
# If you want the union, run the command twice and concatenate the results.
|
||||
# The intersection is harder to achieve with shell tools.
|
||||
class Uses < AbstractCommand
|
||||
include DependenciesHelpers
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def self.uses_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Show formulae and casks that specify <formula> as a dependency; that is, show dependents
|
||||
of <formula>. When given multiple formula arguments, show the intersection
|
||||
of formulae that use <formula>. By default, `uses` shows all formulae and casks that
|
||||
specify <formula> as a required or recommended dependency for their stable builds.
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
Show formulae and casks that specify <formula> as a dependency; that is, show dependents
|
||||
of <formula>. When given multiple formula arguments, show the intersection
|
||||
of formulae that use <formula>. By default, `uses` shows all formulae and casks that
|
||||
specify <formula> as a required or recommended dependency for their stable builds.
|
||||
|
||||
*Note:* `--missing` and `--skip-recommended` have precedence over `--include-*`.
|
||||
EOS
|
||||
switch "--recursive",
|
||||
description: "Resolve more than one level of dependencies."
|
||||
switch "--installed",
|
||||
description: "Only list formulae and casks that are currently installed."
|
||||
switch "--missing",
|
||||
description: "Only list formulae and casks that are not currently installed."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not, to show " \
|
||||
"their dependents."
|
||||
switch "--include-build",
|
||||
description: "Include formulae that specify <formula> as a `:build` dependency."
|
||||
switch "--include-test",
|
||||
description: "Include formulae that specify <formula> as a `:test` dependency."
|
||||
switch "--include-optional",
|
||||
description: "Include formulae that specify <formula> as an `:optional` dependency."
|
||||
switch "--skip-recommended",
|
||||
description: "Skip all formulae that specify <formula> as a `:recommended` dependency."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Include only formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Include only casks."
|
||||
*Note:* `--missing` and `--skip-recommended` have precedence over `--include-*`.
|
||||
EOS
|
||||
switch "--recursive",
|
||||
description: "Resolve more than one level of dependencies."
|
||||
switch "--installed",
|
||||
description: "Only list formulae and casks that are currently installed."
|
||||
switch "--missing",
|
||||
description: "Only list formulae and casks that are not currently installed."
|
||||
switch "--eval-all",
|
||||
description: "Evaluate all available formulae and casks, whether installed or not, to show " \
|
||||
"their dependents."
|
||||
switch "--include-build",
|
||||
description: "Include formulae that specify <formula> as a `:build` dependency."
|
||||
switch "--include-test",
|
||||
description: "Include formulae that specify <formula> as a `:test` dependency."
|
||||
switch "--include-optional",
|
||||
description: "Include formulae that specify <formula> as an `:optional` dependency."
|
||||
switch "--skip-recommended",
|
||||
description: "Skip all formulae that specify <formula> as a `:recommended` dependency."
|
||||
switch "--formula", "--formulae",
|
||||
description: "Include only formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Include only casks."
|
||||
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--installed", "--all"
|
||||
conflicts "--missing", "--installed"
|
||||
conflicts "--formula", "--cask"
|
||||
conflicts "--installed", "--all"
|
||||
conflicts "--missing", "--installed"
|
||||
|
||||
named_args :formula, min: 1
|
||||
end
|
||||
end
|
||||
|
||||
def self.uses
|
||||
args = uses_args.parse
|
||||
|
||||
Formulary.enable_factory_cache!
|
||||
|
||||
used_formulae_missing = false
|
||||
used_formulae = begin
|
||||
args.named.to_formulae
|
||||
rescue FormulaUnavailableError => e
|
||||
opoo e
|
||||
used_formulae_missing = true
|
||||
# If the formula doesn't exist: fake the needed formula object name.
|
||||
# This is a legacy use of OpenStruct that should be refactored.
|
||||
# rubocop:disable Style/OpenStructUse
|
||||
args.named.map { |name| OpenStruct.new name:, full_name: name }
|
||||
# rubocop:enable Style/OpenStructUse
|
||||
end
|
||||
|
||||
use_runtime_dependents = args.installed? &&
|
||||
!used_formulae_missing &&
|
||||
!args.include_build? &&
|
||||
!args.include_test? &&
|
||||
!args.include_optional? &&
|
||||
!args.skip_recommended?
|
||||
|
||||
uses = intersection_of_dependents(use_runtime_dependents, used_formulae, args:)
|
||||
|
||||
return if uses.empty?
|
||||
|
||||
puts Formatter.columns(uses.map(&:full_name).sort)
|
||||
odie "Missing formulae should not have dependents!" if used_formulae_missing
|
||||
end
|
||||
|
||||
def self.intersection_of_dependents(use_runtime_dependents, used_formulae, args:)
|
||||
recursive = args.recursive?
|
||||
show_formulae_and_casks = !args.formula? && !args.cask?
|
||||
includes, ignores = args_includes_ignores(args)
|
||||
|
||||
deps = []
|
||||
if use_runtime_dependents
|
||||
if show_formulae_and_casks || args.formula?
|
||||
deps += used_formulae.map(&:runtime_installed_formula_dependents)
|
||||
.reduce(&:&)
|
||||
.select(&:any_version_installed?)
|
||||
end
|
||||
if show_formulae_and_casks || args.cask?
|
||||
deps += select_used_dependents(
|
||||
dependents(Cask::Caskroom.casks),
|
||||
used_formulae, recursive, includes, ignores
|
||||
)
|
||||
named_args :formula, min: 1
|
||||
end
|
||||
|
||||
deps
|
||||
else
|
||||
all = args.eval_all?
|
||||
sig { override.void }
|
||||
def run
|
||||
Formulary.enable_factory_cache!
|
||||
|
||||
if !args.installed? && !(all || Homebrew::EnvConfig.eval_all?)
|
||||
raise UsageError, "`brew uses` needs `--installed` or `--eval-all` passed or `HOMEBREW_EVAL_ALL` set!"
|
||||
used_formulae_missing = false
|
||||
used_formulae = begin
|
||||
args.named.to_formulae
|
||||
rescue FormulaUnavailableError => e
|
||||
opoo e
|
||||
used_formulae_missing = true
|
||||
# If the formula doesn't exist: fake the needed formula object name.
|
||||
# This is a legacy use of OpenStruct that should be refactored.
|
||||
# rubocop:disable Style/OpenStructUse
|
||||
args.named.map { |name| OpenStruct.new name:, full_name: name }
|
||||
# rubocop:enable Style/OpenStructUse
|
||||
end
|
||||
|
||||
use_runtime_dependents = args.installed? &&
|
||||
!used_formulae_missing &&
|
||||
!args.include_build? &&
|
||||
!args.include_test? &&
|
||||
!args.include_optional? &&
|
||||
!args.skip_recommended?
|
||||
|
||||
uses = intersection_of_dependents(use_runtime_dependents, used_formulae)
|
||||
|
||||
return if uses.empty?
|
||||
|
||||
puts Formatter.columns(uses.map(&:full_name).sort)
|
||||
odie "Missing formulae should not have dependents!" if used_formulae_missing
|
||||
end
|
||||
|
||||
if show_formulae_and_casks || args.formula?
|
||||
deps += args.installed? ? Formula.installed : Formula.all(eval_all: args.eval_all?)
|
||||
end
|
||||
if show_formulae_and_casks || args.cask?
|
||||
deps += args.installed? ? Cask::Caskroom.casks : Cask::Cask.all(eval_all: args.eval_all?)
|
||||
private
|
||||
|
||||
def intersection_of_dependents(use_runtime_dependents, used_formulae)
|
||||
recursive = args.recursive?
|
||||
show_formulae_and_casks = !args.formula? && !args.cask?
|
||||
includes, ignores = args_includes_ignores(args)
|
||||
|
||||
deps = []
|
||||
if use_runtime_dependents
|
||||
if show_formulae_and_casks || args.formula?
|
||||
deps += used_formulae.map(&:runtime_installed_formula_dependents)
|
||||
.reduce(&:&)
|
||||
.select(&:any_version_installed?)
|
||||
end
|
||||
if show_formulae_and_casks || args.cask?
|
||||
deps += select_used_dependents(
|
||||
dependents(Cask::Caskroom.casks),
|
||||
used_formulae, recursive, includes, ignores
|
||||
)
|
||||
end
|
||||
|
||||
deps
|
||||
else
|
||||
all = args.eval_all?
|
||||
|
||||
if !args.installed? && !(all || Homebrew::EnvConfig.eval_all?)
|
||||
raise UsageError, "`brew uses` needs `--installed` or `--eval-all` passed or `HOMEBREW_EVAL_ALL` set!"
|
||||
end
|
||||
|
||||
if show_formulae_and_casks || args.formula?
|
||||
deps += args.installed? ? Formula.installed : Formula.all(eval_all: args.eval_all?)
|
||||
end
|
||||
if show_formulae_and_casks || args.cask?
|
||||
deps += args.installed? ? Cask::Caskroom.casks : Cask::Cask.all(eval_all: args.eval_all?)
|
||||
end
|
||||
|
||||
if args.missing?
|
||||
deps.reject! do |dep|
|
||||
case dep
|
||||
when Formula
|
||||
dep.any_version_installed?
|
||||
when Cask::Cask
|
||||
dep.installed?
|
||||
end
|
||||
end
|
||||
ignores.delete(:satisfied?)
|
||||
end
|
||||
|
||||
select_used_dependents(dependents(deps), used_formulae, recursive, includes, ignores)
|
||||
end
|
||||
end
|
||||
|
||||
if args.missing?
|
||||
deps.reject! do |dep|
|
||||
case dep
|
||||
when Formula
|
||||
dep.any_version_installed?
|
||||
when Cask::Cask
|
||||
dep.installed?
|
||||
def select_used_dependents(dependents, used_formulae, recursive, includes, ignores)
|
||||
dependents.select do |d|
|
||||
deps = if recursive
|
||||
recursive_includes(Dependency, d, includes, ignores)
|
||||
else
|
||||
select_includes(d.deps, ignores, includes)
|
||||
end
|
||||
|
||||
used_formulae.all? do |ff|
|
||||
deps.any? do |dep|
|
||||
match = begin
|
||||
dep.to_formula.full_name == ff.full_name if dep.name.include?("/")
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
next match unless match.nil?
|
||||
|
||||
dep.name == ff.name
|
||||
end
|
||||
rescue FormulaUnavailableError
|
||||
# Silently ignore this case as we don't care about things used in
|
||||
# taps that aren't currently tapped.
|
||||
next
|
||||
end
|
||||
end
|
||||
ignores.delete(:satisfied?)
|
||||
end
|
||||
|
||||
select_used_dependents(dependents(deps), used_formulae, recursive, includes, ignores)
|
||||
end
|
||||
end
|
||||
|
||||
def self.select_used_dependents(dependents, used_formulae, recursive, includes, ignores)
|
||||
dependents.select do |d|
|
||||
deps = if recursive
|
||||
recursive_includes(Dependency, d, includes, ignores)
|
||||
else
|
||||
select_includes(d.deps, ignores, includes)
|
||||
end
|
||||
|
||||
used_formulae.all? do |ff|
|
||||
deps.any? do |dep|
|
||||
match = begin
|
||||
dep.to_formula.full_name == ff.full_name if dep.name.include?("/")
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
next match unless match.nil?
|
||||
|
||||
dep.name == ff.name
|
||||
end
|
||||
rescue FormulaUnavailableError
|
||||
# Silently ignore this case as we don't care about things used in
|
||||
# taps that aren't currently tapped.
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -98,7 +98,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
rescue Exception => e # rubocop:disable Lint/RescueException
|
||||
retry if retry_test?(f, args:)
|
||||
retry if retry_test?(f)
|
||||
ofail "#{f.full_name}: failed"
|
||||
$stderr.puts e, Utils::Backtrace.clean(e)
|
||||
ensure
|
||||
@ -109,7 +109,7 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
def retry_test?(formula, args:)
|
||||
def retry_test?(formula)
|
||||
@test_failed ||= Set.new
|
||||
if args.retry? && @test_failed.add?(formula)
|
||||
oh1 "Testing #{formula.full_name} (again)"
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
|
||||
module Readall
|
||||
class << self
|
||||
undef valid_casks?
|
||||
|
||||
def valid_casks?(tap, os_name: nil, arch: Hardware::CPU.type)
|
||||
return true if os_name == :linux
|
||||
|
||||
|
||||
@ -12,13 +12,13 @@ require "cli/parser"
|
||||
require "cmd/postinstall"
|
||||
|
||||
begin
|
||||
args = Homebrew.postinstall_args.parse
|
||||
args = Homebrew::Cmd::Postinstall.new.args
|
||||
error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
|
||||
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
||||
|
||||
trap("INT", old_trap)
|
||||
|
||||
formula = args.named.to_resolved_formulae.first
|
||||
formula = T.must(args.named.to_resolved_formulae.first)
|
||||
if args.debug?
|
||||
require "debrew"
|
||||
formula.extend(Debrew::Formula)
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/--cache"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew --cache" do
|
||||
RSpec.describe Homebrew::Cmd::Cache do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "prints all cache files for a given Formula", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/--caskroom"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew --caskroom" do
|
||||
RSpec.describe Homebrew::Cmd::Caskroom do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "prints Homebrew's Caskroom", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/--cellar"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew --cellar" do
|
||||
RSpec.describe Homebrew::Cmd::Cellar do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "prints Homebrew's Cellar", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/--env"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew --env" do
|
||||
RSpec.describe Homebrew::Cmd::Env do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
describe "--shell=bash", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/--prefix"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew --prefix" do
|
||||
RSpec.describe Homebrew::Cmd::Prefix do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "prints Homebrew's prefix", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/--repository"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew --repository" do
|
||||
RSpec.describe Homebrew::Cmd::Repository do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "prints Homebrew's repository", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/log"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew log" do
|
||||
RSpec.describe Homebrew::Cmd::Log do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "shows the Git log for a given Formula", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/migrate"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew migrate" do
|
||||
RSpec.describe Homebrew::Cmd::Migrate do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "migrates a renamed Formula", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/missing"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew missing" do
|
||||
RSpec.describe Homebrew::Cmd::Missing do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "prints missing dependencies", :integration_test do
|
||||
|
||||
8
Library/Homebrew/test/cmd/nodenv-sync_spec.rb
Normal file
8
Library/Homebrew/test/cmd/nodenv-sync_spec.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/nodenv-sync"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe Homebrew::Cmd::NodenvSync do
|
||||
it_behaves_like "parseable arguments"
|
||||
end
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/options"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew options" do
|
||||
RSpec.describe Homebrew::Cmd::OptionsCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "prints a given Formula's options", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/outdated"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew outdated" do
|
||||
RSpec.describe Homebrew::Cmd::Outdated do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "outputs JSON", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/pin"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew pin" do
|
||||
RSpec.describe Homebrew::Cmd::Pin do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "pins a Formula's version", :integration_test do
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/postgresql-upgrade-database"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe Homebrew::Cmd::PostgresqlUpgradeDatabase do
|
||||
it_behaves_like "parseable arguments"
|
||||
end
|
||||
@ -1,7 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/postinstall"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew postinstall" do
|
||||
RSpec.describe Homebrew::Cmd::Postinstall do
|
||||
it_behaves_like "parseable arguments"
|
||||
end
|
||||
|
||||
8
Library/Homebrew/test/cmd/pyenv-sync_spec.rb
Normal file
8
Library/Homebrew/test/cmd/pyenv-sync_spec.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/pyenv-sync"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe Homebrew::Cmd::PyenvSync do
|
||||
it_behaves_like "parseable arguments"
|
||||
end
|
||||
8
Library/Homebrew/test/cmd/rbenv-sync_spec.rb
Normal file
8
Library/Homebrew/test/cmd/rbenv-sync_spec.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/rbenv-sync"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe Homebrew::Cmd::RbenvSync do
|
||||
it_behaves_like "parseable arguments"
|
||||
end
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/readall"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew readall" do
|
||||
RSpec.describe Homebrew::Cmd::ReadallCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "imports all Formulae for a given Tap", :integration_test do
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "extend/ENV"
|
||||
require "cmd/reinstall"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew reinstall" do
|
||||
RSpec.describe Homebrew::Cmd::Reinstall do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "reinstalls a Formula", :integration_test do
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
require "cmd/search"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew search" do
|
||||
RSpec.describe Homebrew::Cmd::SearchCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "finds formula in search", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "cmd/tap-info"
|
||||
|
||||
RSpec.describe "brew tap-info" do
|
||||
RSpec.describe Homebrew::Cmd::TapInfo do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "gets information for a given Tap", :integration_test, :needs_network do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "cmd/tap"
|
||||
|
||||
RSpec.describe "brew tap" do
|
||||
RSpec.describe Homebrew::Cmd::TapCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "taps a given Tap", :integration_test do
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/uninstall"
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew uninstall" do
|
||||
RSpec.describe Homebrew::Cmd::UninstallCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "uninstalls a given Formula", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "cmd/unlink"
|
||||
|
||||
RSpec.describe "brew unlink" do
|
||||
RSpec.describe Homebrew::Cmd::UnlinkCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "unlinks a Formula", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "cmd/unpin"
|
||||
|
||||
RSpec.describe "brew unpin" do
|
||||
RSpec.describe Homebrew::Cmd::Unpin do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "unpins a Formula's version", :integration_test do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "cmd/untap"
|
||||
|
||||
RSpec.describe "brew untap" do
|
||||
RSpec.describe Homebrew::Cmd::UntapCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "untaps a given Tap", :integration_test do
|
||||
|
||||
@ -5,7 +5,7 @@ require "formula_versions"
|
||||
require "yaml"
|
||||
require "cmd/shared_examples/args_parse"
|
||||
|
||||
RSpec.describe "brew update-report" do
|
||||
RSpec.describe Homebrew::Cmd::UpdateReport do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
describe Reporter do
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "cmd/upgrade"
|
||||
|
||||
RSpec.describe "brew upgrade" do
|
||||
RSpec.describe Homebrew::Cmd::UpgradeCmd do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
it "upgrades a Formula and cleans up old versions", :integration_test do
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "cmd/uses"
|
||||
require "fileutils"
|
||||
|
||||
RSpec.describe "brew uses" do
|
||||
RSpec.describe Homebrew::Cmd::Uses do
|
||||
include FileUtils
|
||||
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user