Merge pull request #16975 from Homebrew/ported-cmds

Begin porting non-dev commands to use AbstractCommand
This commit is contained in:
Mike McQuaid 2024-03-31 19:28:30 +01:00 committed by GitHub
commit 21dd3c263f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
85 changed files with 2086 additions and 2109 deletions

View File

@ -1,12 +1,15 @@
# typed: strong
# frozen_string_literal: true
require "cli/parser"
module Homebrew
# Subclass this to implement a `brew` command. This is preferred to declaring a named function in the `Homebrew`
# module, because:
# - Each Command lives in an isolated namespace.
# - Each Command implements a defined interface.
# - `args` is available as an ivar, and thus does not need to be passed as an argument to helper methods.
# - Subclasses no longer need to reference `CLI::Parser` or parse args explicitly.
#
# To subclass, implement a `run` method and provide a `cmd_args` block to document the command and its allowed args.
# To generate method signatures for command args, run `brew typecheck --update`.

View File

@ -217,7 +217,7 @@ class Build
end
begin
args = Homebrew.install_args.parse
args = Homebrew::Cmd::InstallCmd.new.args
Context.current = args.context
error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)

View File

@ -1,14 +1,12 @@
# typed: strict
# frozen_string_literal: true
require "cli/parser"
require "abstract_command"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def analytics_args
Homebrew::CLI::Parser.new do
module Cmd
class Analytics < AbstractCommand
cmd_args do
description <<~EOS
Control Homebrew's anonymous aggregate user behaviour analytics.
Read more at <https://docs.brew.sh/Analytics>.
@ -22,12 +20,9 @@ module Homebrew
named_args %w[state on off regenerate-uuid], max: 1
end
end
sig { void }
def analytics
args = analytics_args.parse
sig { override.void }
def run
case args.named.first
when nil, "state"
if Utils::Analytics.disabled?
@ -49,3 +44,5 @@ module Homebrew
end
end
end
end
end

View File

@ -1,13 +1,13 @@
# typed: strict
# frozen_string_literal: true
require "abstract_command"
require "cleanup"
require "cli/parser"
module Homebrew
sig { returns(CLI::Parser) }
def self.autoremove_args
Homebrew::CLI::Parser.new do
module Cmd
class Autoremove < AbstractCommand
cmd_args do
description <<~EOS
Uninstall formulae that were only installed as a dependency of another formula and are now no longer needed.
EOS
@ -16,12 +16,11 @@ module Homebrew
named_args :none
end
end
sig { void }
def self.autoremove
args = autoremove_args.parse
sig { override.void }
def run
Cleanup.autoremove(dry_run: args.dry_run?)
end
end
end
end

View File

@ -1,15 +1,13 @@
# typed: strict
# frozen_string_literal: true
require "abstract_command"
require "cleanup"
require "cli/parser"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def cleanup_args
Homebrew::CLI::Parser.new do
module Cmd
class CleanupCmd < AbstractCommand
cmd_args do
days = Homebrew::EnvConfig::ENVS[:HOMEBREW_CLEANUP_MAX_AGE_DAYS][:default]
description <<~EOS
Remove stale lock files and outdated downloads for all formulae and casks,
@ -31,12 +29,9 @@ module Homebrew
named_args [:formula, :cask]
end
end
sig { void }
def cleanup
args = cleanup_args.parse
sig { override.void }
def run
days = args.prune.presence&.then do |prune|
case prune
when /\A\d+\Z/
@ -73,3 +68,5 @@ module Homebrew
EOS
end
end
end
end

View File

@ -1,14 +1,12 @@
# typed: strict
# frozen_string_literal: true
require "cli/parser"
require "abstract_command"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def commands_args
Homebrew::CLI::Parser.new do
module Cmd
class CommandsCmd < AbstractCommand
cmd_args do
description <<~EOS
Show lists of built-in and external commands.
EOS
@ -20,12 +18,9 @@ module Homebrew
named_args :none
end
end
sig { void }
def commands
args = commands_args.parse
sig { override.void }
def run
if args.quiet?
puts Formatter.columns(Commands.commands(aliases: args.include_aliases?))
return
@ -47,3 +42,5 @@ module Homebrew
end
end
end
end
end

View File

@ -1,15 +1,13 @@
# typed: strict
# frozen_string_literal: true
require "cli/parser"
require "abstract_command"
require "completions"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def completions_args
Homebrew::CLI::Parser.new do
module Cmd
class CompletionsCmd < AbstractCommand
cmd_args do
description <<~EOS
Control whether Homebrew automatically links external tap shell completion files.
Read more at <https://docs.brew.sh/Shell-Completion>.
@ -23,12 +21,9 @@ module Homebrew
named_args %w[state link unlink], max: 1
end
end
sig { void }
def completions
args = completions_args.parse
sig { override.void }
def run
case args.named.first
when nil, "state"
if Completions.link_completions?
@ -47,3 +42,5 @@ module Homebrew
end
end
end
end
end

View File

@ -1,15 +1,13 @@
# typed: strict
# frozen_string_literal: true
require "abstract_command"
require "system_config"
require "cli/parser"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def config_args
Homebrew::CLI::Parser.new do
module Cmd
class Config < AbstractCommand
cmd_args do
description <<~EOS
Show Homebrew and system configuration info useful for debugging. If you file
a bug report, you will be required to provide this information.
@ -17,12 +15,11 @@ module Homebrew
named_args :none
end
end
sig { void }
def config
config_args.parse
sig { override.void }
def run
SystemConfig.dump_verbose_config
end
end
end
end

View File

@ -1,17 +1,16 @@
# typed: true
# frozen_string_literal: true
require "abstract_command"
require "formula"
require "cli/parser"
require "cask/caskroom"
require "dependencies_helpers"
module Homebrew
extend DependenciesHelpers
sig { returns(CLI::Parser) }
def self.deps_args
Homebrew::CLI::Parser.new do
module Cmd
class Deps < AbstractCommand
include DependenciesHelpers
cmd_args do
description <<~EOS
Show dependencies for <formula>. When given multiple formula arguments,
show the intersection of dependencies for each formula. By default, `deps`
@ -80,11 +79,9 @@ module Homebrew
named_args [:formula, :cask]
end
end
def self.deps
args = deps_args.parse
sig { override.void }
def run
all = args.eval_all?
Formulary.enable_factory_cache!
@ -119,7 +116,7 @@ module Homebrew
end
if args.graph?
dot_code = dot_code(dependents, recursive:, args:)
dot_code = dot_code(dependents, recursive:)
if args.dot?
puts dot_code
else
@ -128,15 +125,15 @@ module Homebrew
return
end
puts_deps_tree(dependents, recursive:, args:)
puts_deps_tree(dependents, recursive:)
return
elsif all
puts_deps(sorted_dependents(
Formula.all(eval_all: args.eval_all?) + Cask::Cask.all(eval_all: args.eval_all?),
), recursive:, args:)
), recursive:)
return
elsif !args.no_named? && args.for_each?
puts_deps(sorted_dependents(args.named.to_formulae_and_casks), recursive:, args:)
puts_deps(sorted_dependents(args.named.to_formulae_and_casks), recursive:)
return
end
@ -151,31 +148,33 @@ module Homebrew
else
sorted_dependents(Formula.installed + Cask::Caskroom.casks)
end
puts_deps(sorted_dependents_formulae_and_casks, recursive:, args:)
puts_deps(sorted_dependents_formulae_and_casks, recursive:)
return
end
dependents = dependents(args.named.to_formulae_and_casks)
check_head_spec(dependents) if args.HEAD?
all_deps = deps_for_dependents(dependents, recursive:, args:, &(args.union? ? :| : :&))
condense_requirements(all_deps, args:)
all_deps.map! { |d| dep_display_name(d, args:) }
all_deps = deps_for_dependents(dependents, recursive:, &(args.union? ? :| : :&))
condense_requirements(all_deps)
all_deps.map! { |d| dep_display_name(d) }
all_deps.uniq!
all_deps.sort! unless args.topological?
puts all_deps
end
def self.sorted_dependents(formulae_or_casks)
private
def sorted_dependents(formulae_or_casks)
dependents(formulae_or_casks).sort_by(&:name)
end
def self.condense_requirements(deps, args:)
def condense_requirements(deps)
deps.select! { |dep| dep.is_a?(Dependency) } unless args.include_requirements?
deps.select! { |dep| dep.is_a?(Requirement) || dep.installed? } if args.installed?
end
def self.dep_display_name(dep, args:)
def dep_display_name(dep)
str = if dep.is_a? Requirement
if args.include_requirements?
":#{dep.display_s}"
@ -201,7 +200,7 @@ module Homebrew
str
end
def self.deps_for_dependent(dependency, args:, recursive: false)
def deps_for_dependent(dependency, recursive: false)
includes, ignores = args_includes_ignores(args)
deps = dependency.runtime_dependencies if @use_runtime_dependencies
@ -217,31 +216,31 @@ module Homebrew
deps + reqs.to_a
end
def self.deps_for_dependents(dependents, args:, recursive: false, &block)
dependents.map { |d| deps_for_dependent(d, recursive:, args:) }.reduce(&block)
def deps_for_dependents(dependents, recursive: false, &block)
dependents.map { |d| deps_for_dependent(d, recursive:) }.reduce(&block)
end
def self.check_head_spec(dependents)
def check_head_spec(dependents)
headless = dependents.select { |d| d.is_a?(Formula) && d.active_spec_sym != :head }
.to_sentence two_words_connector: " or ", last_word_connector: " or "
opoo "No head spec for #{headless}, using stable spec instead" unless headless.empty?
end
def self.puts_deps(dependents, args:, recursive: false)
def puts_deps(dependents, recursive: false)
check_head_spec(dependents) if args.HEAD?
dependents.each do |dependent|
deps = deps_for_dependent(dependent, recursive:, args:)
condense_requirements(deps, args:)
deps = deps_for_dependent(dependent, recursive:)
condense_requirements(deps)
deps.sort_by!(&:name)
deps.map! { |d| dep_display_name(d, args:) }
deps.map! { |d| dep_display_name(d) }
puts "#{dependent.full_name}: #{deps.join(" ")}"
end
end
def self.dot_code(dependents, recursive:, args:)
def dot_code(dependents, recursive:)
dep_graph = {}
dependents.each do |d|
graph_deps(d, dep_graph:, recursive:, args:)
graph_deps(d, dep_graph:, recursive:)
end
dot_code = dep_graph.map do |d, deps|
@ -261,10 +260,10 @@ module Homebrew
"digraph {\n#{dot_code}\n}"
end
def self.graph_deps(formula, dep_graph:, recursive:, args:)
def graph_deps(formula, dep_graph:, recursive:)
return if dep_graph.key?(formula)
dependables = dependables(formula, args:)
dependables = dependables(formula)
dep_graph[formula] = dependables
return unless recursive
@ -273,21 +272,20 @@ module Homebrew
graph_deps(Formulary.factory(dep.name),
dep_graph:,
recursive: true,
args:)
recursive: true)
end
end
def self.puts_deps_tree(dependents, args:, recursive: false)
def puts_deps_tree(dependents, recursive: false)
check_head_spec(dependents) if args.HEAD?
dependents.each do |d|
puts d.full_name
recursive_deps_tree(d, dep_stack: [], prefix: "", recursive:, args:)
recursive_deps_tree(d, dep_stack: [], prefix: "", recursive:)
puts
end
end
def self.dependables(formula, args:)
def dependables(formula)
includes, ignores = args_includes_ignores(args)
deps = @use_runtime_dependencies ? formula.runtime_dependencies : formula.deps
deps = select_includes(deps, ignores, includes)
@ -296,8 +294,8 @@ module Homebrew
reqs + deps
end
def self.recursive_deps_tree(formula, dep_stack:, prefix:, recursive:, args:)
dependables = dependables(formula, args:)
def recursive_deps_tree(formula, dep_stack:, prefix:, recursive:)
dependables = dependables(formula)
max = dependables.length - 1
dep_stack.push formula.name
dependables.each_with_index do |dep, i|
@ -307,7 +305,7 @@ module Homebrew
"├──"
end
display_s = "#{tree_lines} #{dep_display_name(dep, args:)}"
display_s = "#{tree_lines} #{dep_display_name(dep)}"
# Detect circular dependencies and consider them a failure if present.
is_circular = dep_stack.include?(dep.name)
@ -331,10 +329,11 @@ module Homebrew
recursive_deps_tree(Formulary.factory(dep.name),
dep_stack:,
prefix: prefix + prefix_addition,
recursive: true,
args:)
recursive: true)
end
dep_stack.pop
end
end
end
end

View File

@ -1,17 +1,15 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "abstract_command"
require "descriptions"
require "search"
require "description_cache_store"
require "cli/parser"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def desc_args
Homebrew::CLI::Parser.new do
module Cmd
class Desc < AbstractCommand
cmd_args do
description <<~EOS
Display <formula>'s name and one-line description.
The cache is created on the first search, making that search slower than subsequent ones.
@ -37,11 +35,9 @@ module Homebrew
named_args [:formula, :cask, :text_or_regex], min: 1
end
end
def desc
args = desc_args.parse
sig { override.void }
def run
if !args.eval_all? && !Homebrew::EnvConfig.eval_all?
raise UsageError, "`brew desc` needs `--eval-all` passed or `HOMEBREW_EVAL_ALL` set!"
end
@ -57,11 +53,14 @@ module Homebrew
if search_type.blank?
desc = {}
args.named.to_formulae_and_casks.each do |formula_or_cask|
if formula_or_cask.is_a? Formula
case formula_or_cask
when Formula
desc[formula_or_cask.full_name] = formula_or_cask.desc
else
when Cask::Cask
description = formula_or_cask.desc.presence || Formatter.warning("[no description]")
desc[formula_or_cask.full_name] = "(#{formula_or_cask.name.join(", ")}) #{description}"
else
raise TypeError, "Unsupported formula_or_cask type: #{formula_or_cask.class}"
end
end
Descriptions.new(desc).print
@ -72,3 +71,5 @@ module Homebrew
end
end
end
end
end

View File

@ -1,14 +1,12 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "cli/parser"
require "abstract_command"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def developer_args
Homebrew::CLI::Parser.new do
module Cmd
class Developer < AbstractCommand
cmd_args do
description <<~EOS
Control Homebrew's developer mode. When developer mode is enabled,
`brew update` will update Homebrew to the latest commit on the `master`
@ -23,11 +21,9 @@ module Homebrew
named_args %w[state on off], max: 1
end
end
def developer
args = developer_args.parse
sig { override.void }
def run
env_vars = []
env_vars << "HOMEBREW_DEVELOPER" if Homebrew::EnvConfig.developer?
env_vars << "HOMEBREW_UPDATE_TO_TAG" if Homebrew::EnvConfig.update_to_tag?
@ -38,7 +34,8 @@ module Homebrew
case args.named.first
when nil, "state"
if env_vars.any?
puts "Developer mode is enabled because #{env_vars.to_sentence} #{(env_vars.count == 1) ? "is" : "are"} set."
verb = (env_vars.count == 1) ? "is" : "are"
puts "Developer mode is enabled because #{env_vars.to_sentence} #{verb} set."
elsif Homebrew::Settings.read("devcmdrun") == "true"
puts "Developer mode is enabled."
else
@ -54,3 +51,5 @@ module Homebrew
end
end
end
end
end

View File

@ -1,22 +1,21 @@
# typed: strict
# frozen_string_literal: true
require "cli/parser"
require "abstract_command"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def docs_args
Homebrew::CLI::Parser.new do
module Cmd
class Docs < AbstractCommand
cmd_args do
description <<~EOS
Open Homebrew's online documentation at <#{HOMEBREW_DOCS_WWW}> in a browser.
EOS
end
end
sig { void }
def docs
sig { override.void }
def run
exec_browser HOMEBREW_DOCS_WWW
end
end
end
end

View File

@ -1,14 +1,14 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "abstract_command"
require "diagnostic"
require "cli/parser"
require "cask/caskroom"
module Homebrew
sig { returns(CLI::Parser) }
def self.doctor_args
Homebrew::CLI::Parser.new do
module Cmd
class Doctor < AbstractCommand
cmd_args do
description <<~EOS
Check your system for potential problems. Will exit with a non-zero status
if any potential problems are found.
@ -25,12 +25,10 @@ module Homebrew
named_args :diagnostic_check
end
end
def self.doctor
args = doctor_args.parse
inject_dump_stats!(Diagnostic::Checks, /^check_*/) if args.audit_debug?
sig { override.void }
def run
Homebrew.inject_dump_stats!(Diagnostic::Checks, /^check_*/) if args.audit_debug?
checks = Diagnostic::Checks.new(verbose: args.verbose?)
@ -78,3 +76,5 @@ module Homebrew
puts "Your system is ready to brew." if !Homebrew.failed? && !args.quiet?
end
end
end
end

View File

@ -1,19 +1,18 @@
# typed: true
# frozen_string_literal: true
require "abstract_command"
require "formula"
require "fetch"
require "cli/parser"
require "cask/download"
module Homebrew
extend Fetch
module Cmd
class FetchCmd < AbstractCommand
include Fetch
FETCH_MAX_TRIES = 5
sig { returns(CLI::Parser) }
def self.fetch_args
Homebrew::CLI::Parser.new do
cmd_args do
description <<~EOS
Download a bottle (if available) or source packages for <formula>e
and binaries for <cask>s. For files, also print SHA-256 checksums.
@ -67,11 +66,9 @@ module Homebrew
named_args [:formula, :cask], min: 1
end
end
def self.fetch
args = fetch_args.parse
sig { override.void }
def run
Formulary.enable_factory_cache!
bucket = if args.deps?
@ -131,10 +128,10 @@ module Homebrew
begin
bottle.fetch_tab
rescue DownloadError
retry if retry_fetch?(bottle, args:)
retry if retry_fetch?(bottle)
raise
end
fetch_formula(bottle, args:)
fetch_formula(bottle)
rescue Interrupt
raise
rescue => e
@ -150,14 +147,14 @@ module Homebrew
next if fetched_bottle
fetch_formula(formula, args:)
fetch_formula(formula)
formula.resources.each do |r|
fetch_resource(r, args:)
r.patches.each { |p| fetch_patch(p, args:) if p.external? }
fetch_resource(r)
r.patches.each { |p| fetch_patch(p) if p.external? }
end
formula.patchlist.each { |p| fetch_patch(p, args:) if p.external? }
formula.patchlist.each { |p| fetch_patch(p) if p.external? }
end
end
else
@ -179,43 +176,45 @@ module Homebrew
quarantine = true if quarantine.nil?
download = Cask::Download.new(cask, quarantine:)
fetch_cask(download, args:)
fetch_cask(download)
end
end
end
end
end
def self.fetch_resource(resource, args:)
private
def fetch_resource(resource)
puts "Resource: #{resource.name}"
fetch_fetchable resource, args:
fetch_fetchable resource
rescue ChecksumMismatchError => e
retry if retry_fetch?(resource, args:)
retry if retry_fetch?(resource)
opoo "Resource #{resource.name} reports different sha256: #{e.expected}"
end
def self.fetch_formula(formula, args:)
fetch_fetchable(formula, args:)
def fetch_formula(formula)
fetch_fetchable(formula)
rescue ChecksumMismatchError => e
retry if retry_fetch?(formula, args:)
retry if retry_fetch?(formula)
opoo "Formula reports different sha256: #{e.expected}"
end
def self.fetch_cask(cask_download, args:)
fetch_fetchable(cask_download, args:)
def fetch_cask(cask_download)
fetch_fetchable(cask_download)
rescue ChecksumMismatchError => e
retry if retry_fetch?(cask_download, args:)
retry if retry_fetch?(cask_download)
opoo "Cask reports different sha256: #{e.expected}"
end
def self.fetch_patch(patch, args:)
fetch_fetchable(patch, args:)
def fetch_patch(patch)
fetch_fetchable(patch)
rescue ChecksumMismatchError => e
opoo "Patch reports different sha256: #{e.expected}"
Homebrew.failed = true
end
def self.retry_fetch?(formula, args:)
def retry_fetch?(formula)
@fetch_tries ||= Hash.new { |h, k| h[k] = 1 }
if args.retry? && (@fetch_tries[formula] < FETCH_MAX_TRIES)
wait = 2 ** @fetch_tries[formula]
@ -234,7 +233,7 @@ module Homebrew
end
end
def self.fetch_fetchable(formula, args:)
def fetch_fetchable(formula)
formula.clear_cache if args.force?
already_fetched = formula.cached_download.exist?
@ -242,7 +241,7 @@ module Homebrew
begin
download = formula.fetch(verify_download_integrity: false)
rescue DownloadError
retry if retry_fetch?(formula, args:)
retry if retry_fetch?(formula)
raise
end
@ -254,3 +253,5 @@ module Homebrew
formula.verify_download_integrity(download)
end
end
end
end

View File

@ -1,21 +1,18 @@
# typed: true
# frozen_string_literal: true
require "abstract_command"
require "formula"
require "install"
require "system_config"
require "stringio"
require "socket"
require "cli/parser"
module Homebrew
extend Install
module_function
sig { returns(CLI::Parser) }
def gist_logs_args
Homebrew::CLI::Parser.new do
module Cmd
class GistLogs < AbstractCommand
include Install
cmd_args do
description <<~EOS
Upload logs for a failed build of <formula> to a new Gist. Presents an
error message if no logs are found.
@ -31,9 +28,17 @@ module Homebrew
named_args :formula, number: 1
end
sig { override.void }
def run
Install.perform_preinstall_checks(all_fatal: true)
Install.perform_build_from_source_checks(all_fatal: true)
gistify_logs(args.named.to_resolved_formulae.first)
end
def gistify_logs(formula, args:)
private
def gistify_logs(formula)
files = load_logs(formula.logs)
build_time = formula.logs.ctime
timestamp = build_time.strftime("%Y-%m-%d_%H-%M-%S")
@ -73,7 +78,10 @@ module Homebrew
EOS
end
url = GitHub.create_issue(formula.tap, "#{formula.name} failed to build on #{OS_VERSION}", url) if args.new_issue?
if args.new_issue?
url = GitHub.create_issue(formula.tap, "#{formula.name} failed to build on #{OS_VERSION}",
url)
end
puts url if url
end
@ -119,12 +127,6 @@ module Homebrew
logs
end
def gist_logs
args = gist_logs_args.parse
Install.perform_preinstall_checks(all_fatal: true)
Install.perform_build_from_source_checks(all_fatal: true)
gistify_logs(args.named.to_resolved_formulae.first, args:)
end
end
end

View File

@ -1,11 +1,16 @@
# typed: strict
# typed: strong
# frozen_string_literal: true
require "abstract_command"
require "help"
module Homebrew
sig { returns(T.noreturn) }
def help
module Cmd
class HelpCmd < AbstractCommand
sig { override.void }
def run
Help.help
end
end
end
end

View File

@ -1,15 +1,13 @@
# typed: true
# frozen_string_literal: true
require "cli/parser"
require "abstract_command"
require "formula"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def home_args
Homebrew::CLI::Parser.new do
module Cmd
class Home < AbstractCommand
cmd_args do
description <<~EOS
Open a <formula> or <cask>'s homepage in a browser, or open
Homebrew's own homepage if no argument is provided.
@ -23,12 +21,9 @@ module Homebrew
named_args [:formula, :cask]
end
end
sig { void }
def home
args = home_args.parse
sig { override.void }
def run
if args.no_named?
exec_browser HOMEBREW_WWW
return
@ -44,6 +39,8 @@ module Homebrew
exec_browser(*T.unsafe(homepages))
end
private
def name_of(formula_or_cask)
if formula_or_cask.is_a? Formula
"Formula #{formula_or_cask.name}"
@ -52,3 +49,5 @@ module Homebrew
end
end
end
end
end

View File

@ -1,9 +1,9 @@
# typed: true
# frozen_string_literal: true
require "abstract_command"
require "missing_formula"
require "caveats"
require "cli/parser"
require "options"
require "formula"
require "keg"
@ -14,15 +14,13 @@ require "deprecate_disable"
require "api"
module Homebrew
module_function
module Cmd
class Info < AbstractCommand
VALID_DAYS = %w[30 90 365].freeze
VALID_FORMULA_CATEGORIES = %w[install install-on-request build-error].freeze
VALID_CATEGORIES = (VALID_FORMULA_CATEGORIES + %w[cask-install os-version]).freeze
sig { returns(CLI::Parser) }
def info_args
Homebrew::CLI::Parser.new do
cmd_args do
description <<~EOS
Display brief statistics for your Homebrew installation.
If a <formula> or <cask> is provided, show summary of information about it.
@ -74,12 +72,9 @@ module Homebrew
named_args [:formula, :cask]
end
end
sig { void }
def info
args = info_args.parse
sig { override.void }
def run
if args.analytics?
if args.days.present? && VALID_DAYS.exclude?(args.days)
raise UsageError, "`--days` must be one of #{VALID_DAYS.join(", ")}."
@ -96,11 +91,11 @@ module Homebrew
end
end
print_analytics(args:)
print_analytics
elsif args.json
all = args.eval_all?
print_json(all, args:)
print_json(all)
elsif args.github?
raise FormulaOrCaskUnspecifiedError if args.no_named?
@ -108,10 +103,20 @@ module Homebrew
elsif args.no_named?
print_statistics
else
print_info(args:)
print_info
end
end
def github_remote_path(remote, path)
if remote =~ %r{^(?:https?://|git(?:@|://))github\.com[:/](.+)/(.+?)(?:\.git)?$}
"https://github.com/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}/blob/HEAD/#{path}"
else
"#{remote}/#{path}"
end
end
private
sig { void }
def print_statistics
return unless HOMEBREW_CELLAR.exist?
@ -120,8 +125,8 @@ module Homebrew
puts "#{Utils.pluralize("keg", count, include_count: true)}, #{HOMEBREW_CELLAR.dup.abv}"
end
sig { params(args: CLI::Args).void }
def print_analytics(args:)
sig { void }
def print_analytics
if args.no_named?
Utils::Analytics.output(args:)
return
@ -143,16 +148,16 @@ module Homebrew
end
end
sig { params(args: CLI::Args).void }
def print_info(args:)
sig { void }
def print_info
args.named.to_formulae_and_casks_and_unavailable.each_with_index do |obj, i|
puts unless i.zero?
case obj
when Formula
info_formula(obj, args:)
info_formula(obj)
when Cask::Cask
info_cask(obj, args:)
info_cask(obj)
when FormulaUnreadableError, FormulaClassUnavailableError,
TapFormulaUnreadableError, TapFormulaClassUnavailableError,
Cask::CaskUnreadableError
@ -184,8 +189,8 @@ module Homebrew
version_hash[version]
end
sig { params(all: T::Boolean, args: T.untyped).void }
def print_json(all, args:)
sig { params(all: T::Boolean).void }
def print_json(all)
raise FormulaOrCaskUnspecifiedError if !(all || args.installed?) && args.no_named?
json = case json_version(args.json)
@ -235,14 +240,6 @@ module Homebrew
puts JSON.pretty_generate(json)
end
def github_remote_path(remote, path)
if remote =~ %r{^(?:https?://|git(?:@|://))github\.com[:/](.+)/(.+?)(?:\.git)?$}
"https://github.com/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}/blob/HEAD/#{path}"
else
"#{remote}/#{path}"
end
end
def github_info(formula_or_cask)
return formula_or_cask.path if formula_or_cask.tap.blank? || formula_or_cask.tap.remote.blank?
@ -262,7 +259,7 @@ module Homebrew
github_remote_path(formula_or_cask.tap.remote, path)
end
def info_formula(formula, args:)
def info_formula(formula)
specs = []
if (stable = formula.stable)
@ -369,9 +366,11 @@ module Homebrew
"#{dep.name} #{dep.option_tags.map { |o| "--#{o}" }.join(" ")}"
end
def info_cask(cask, args:)
def info_cask(cask)
require "cask/info"
Cask::Info.info(cask)
end
end
end
end

View File

@ -1,6 +1,7 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "abstract_command"
require "cask/config"
require "cask/installer"
require "cask_dependent"
@ -9,13 +10,12 @@ require "formula_installer"
require "development_tools"
require "install"
require "cleanup"
require "cli/parser"
require "upgrade"
module Homebrew
sig { returns(CLI::Parser) }
def self.install_args
Homebrew::CLI::Parser.new do
module Cmd
class InstallCmd < AbstractCommand
cmd_args do
description <<~EOS
Install a <formula> or <cask>. Additional options specific to a <formula> may be
appended to the command.
@ -50,8 +50,9 @@ module Homebrew
}],
[:switch, "--ignore-dependencies", {
description: "An unsupported Homebrew development option to skip installing any dependencies of any " \
"kind. If the dependencies are not already present, the formula will have issues. If you're " \
"not developing Homebrew, consider adjusting your PATH rather than using this option.",
"kind. If the dependencies are not already present, the formula will have issues. If " \
"you're not developing Homebrew, consider adjusting your PATH rather than using this " \
"option.",
}],
[:switch, "--only-dependencies", {
description: "Install the dependencies with specified options but do not install the " \
@ -161,11 +162,9 @@ module Homebrew
named_args [:formula, :cask], min: 1
end
end
def self.install
args = install_args.parse
sig { override.void }
def run
if args.env.present?
# Can't use `replacement: false` because `install_args` are used by
# `build.rb`. Instead, `hide_from_man_page` and don't do anything with
@ -194,8 +193,10 @@ module Homebrew
end
begin
formulae, casks = args.named.to_formulae_and_casks(warn: false)
.partition { |formula_or_cask| formula_or_cask.is_a?(Formula) }
formulae, casks = T.cast(
args.named.to_formulae_and_casks(warn: false).partition { _1.is_a?(Formula) },
[T::Array[Formula], T::Array[Cask::Cask]],
)
rescue FormulaOrCaskUnavailableError, Cask::CaskUnavailableError
cask_tap = CoreCaskTap.instance
if !cask_tap.installed? && (args.cask? || Tap.untapped_official_taps.exclude?(cask_tap.name))
@ -406,3 +407,5 @@ module Homebrew
odie "No #{package_types.join(" or ")} found for #{name}."
end
end
end
end

View File

@ -1,16 +1,14 @@
# typed: true
# frozen_string_literal: true
require "abstract_command"
require "formula"
require "cask_dependent"
require "cli/parser"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def leaves_args
Homebrew::CLI::Parser.new do
module Cmd
class Leaves < AbstractCommand
cmd_args do
description <<~EOS
List installed formulae that are not dependencies of another installed formula or cask.
EOS
@ -23,19 +21,9 @@ module Homebrew
named_args :none
end
end
def installed_on_request?(formula)
Tab.for_keg(formula.any_installed_keg).installed_on_request
end
def installed_as_dependency?(formula)
Tab.for_keg(formula.any_installed_keg).installed_as_dependency
end
def leaves
args = leaves_args.parse
sig { override.void }
def run
leaves_list = Formula.installed - Formula.installed.flat_map(&:runtime_formula_dependencies)
casks_runtime_dependencies = Cask::Caskroom.casks.flat_map do |cask|
CaskDependent.new(cask).runtime_dependencies.map(&:to_formula)
@ -48,4 +36,16 @@ module Homebrew
.sort
.each(&method(:puts))
end
private
def installed_on_request?(formula)
Tab.for_keg(formula.any_installed_keg).installed_on_request
end
def installed_as_dependency?(formula)
Tab.for_keg(formula.any_installed_keg).installed_as_dependency
end
end
end
end

View File

@ -1,16 +1,14 @@
# typed: true
# frozen_string_literal: true
require "abstract_command"
require "caveats"
require "cli/parser"
require "unlink"
module Homebrew
module_function
sig { returns(CLI::Parser) }
def link_args
Homebrew::CLI::Parser.new do
module Cmd
class Link < AbstractCommand
cmd_args do
description <<~EOS
Symlink all of <formula>'s installed files into Homebrew's prefix.
This is done automatically when you install formulae but can be useful
@ -28,11 +26,9 @@ module Homebrew
named_args :installed_formula, min: 1
end
end
def link
args = link_args.parse
sig { override.void }
def run
options = {
overwrite: args.overwrite?,
dry_run: args.dry_run?,
@ -86,7 +82,8 @@ module Homebrew
end
if keg_only
if HOMEBREW_PREFIX.to_s == HOMEBREW_DEFAULT_PREFIX && formula.present? && formula.keg_only_reason.by_macos?
if HOMEBREW_PREFIX.to_s == HOMEBREW_DEFAULT_PREFIX && formula.present? &&
formula.keg_only_reason.by_macos?
caveats = Caveats.new(formula)
opoo <<~EOS
Refusing to link macOS provided/shadowed software: #{keg.name}
@ -122,6 +119,8 @@ module Homebrew
end
end
private
def puts_keg_only_path_message(keg)
bin = keg/"bin"
sbin = keg/"sbin"
@ -133,3 +132,5 @@ module Homebrew
puts " #{Utils::Shell.prepend_path_in_profile(opt/"sbin")}" if sbin.directory?
end
end
end
end

View File

@ -177,7 +177,10 @@ module Commands
external_commands_file.atomic_write("#{external_commands.sort.join("\n")}\n")
end
sig { params(command: String).returns(T.nilable(T::Array[[String, String]])) }
def self.command_options(command)
return if command == "help"
path = self.path(command)
return if path.blank?
@ -207,7 +210,7 @@ module Commands
if (cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path))
if short
cmd_parser.description.split(DESCRIPTION_SPLITTING_PATTERN).first
cmd_parser.description&.split(DESCRIPTION_SPLITTING_PATTERN)&.first
else
cmd_parser.description
end

View File

@ -15,7 +15,6 @@ require "style"
require "date"
require "missing_formula"
require "digest"
require "cli/parser"
require "json"
require "formula_auditor"
require "tap_auditor"

View File

@ -8,7 +8,6 @@ require "utils/bottles"
require "tab"
require "keg"
require "formula_versions"
require "cli/parser"
require "utils/inreplace"
require "erb"
require "utils/gzip"
@ -108,6 +107,110 @@ module Homebrew
end
end
def generate_sha256_line(tag, digest, cellar, tag_column, digest_column)
line = "sha256 "
tag_column += line.length
digest_column += line.length
if cellar.is_a?(Symbol)
line += "cellar: :#{cellar},"
elsif cellar_parameter_needed?(cellar)
line += %Q(cellar: "#{cellar}",)
end
line += " " * (tag_column - line.length)
line += "#{tag}:"
line += " " * (digest_column - line.length)
%Q(#{line}"#{digest}")
end
def bottle_output(bottle, root_url_using)
cellars = bottle.checksums.filter_map do |checksum|
cellar = checksum["cellar"]
next unless cellar_parameter_needed? cellar
case cellar
when String
%Q("#{cellar}")
when Symbol
":#{cellar}"
end
end
tag_column = cellars.empty? ? 0 : "cellar: #{cellars.max_by(&:length)}, ".length
tags = bottle.checksums.map { |checksum| checksum["tag"] }
# Start where the tag ends, add the max length of the tag, add two for the `: `
digest_column = tag_column + tags.max_by(&:length).length + 2
sha256_lines = bottle.checksums.map do |checksum|
generate_sha256_line(checksum["tag"], checksum["digest"], checksum["cellar"], tag_column, digest_column)
end
erb_binding = bottle.instance_eval { binding }
erb_binding.local_variable_set(:sha256_lines, sha256_lines)
erb_binding.local_variable_set(:root_url_using, root_url_using)
erb = ERB.new BOTTLE_ERB
erb.result(erb_binding).gsub(/^\s*$\n/, "")
end
def parse_json_files(filenames)
filenames.map do |filename|
JSON.parse(File.read(filename))
end
end
def merge_json_files(json_files)
json_files.reduce({}) do |hash, json_file|
json_file.each_value do |json_hash|
json_bottle = json_hash["bottle"]
cellar = json_bottle.delete("cellar")
json_bottle["tags"].each_value do |json_platform|
json_platform["cellar"] ||= cellar
end
end
hash.deep_merge(json_file)
end
end
def merge_bottle_spec(old_keys, old_bottle_spec, new_bottle_hash)
mismatches = []
checksums = []
new_values = {
root_url: new_bottle_hash["root_url"],
rebuild: new_bottle_hash["rebuild"],
}
skip_keys = [:sha256, :cellar]
old_keys.each do |key|
next if skip_keys.include?(key)
old_value = old_bottle_spec.send(key).to_s
new_value = new_values[key].to_s
next if old_value.present? && new_value == old_value
mismatches << "#{key}: old: #{old_value.inspect}, new: #{new_value.inspect}"
end
return [mismatches, checksums] if old_keys.exclude? :sha256
old_bottle_spec.collector.each_tag do |tag|
old_tag_spec = old_bottle_spec.collector.specification_for(tag)
old_hexdigest = old_tag_spec.checksum.hexdigest
old_cellar = old_tag_spec.cellar
new_value = new_bottle_hash.dig("tags", tag.to_s)
if new_value.present? && new_value["sha256"] != old_hexdigest
mismatches << "sha256 #{tag}: old: #{old_hexdigest.inspect}, new: #{new_value["sha256"].inspect}"
elsif new_value.present? && new_value["cellar"] != old_cellar.to_s
mismatches << "cellar #{tag}: old: #{old_cellar.to_s.inspect}, new: #{new_value["cellar"].inspect}"
else
checksums << { cellar: old_cellar, tag.to_sym => old_hexdigest }
end
end
[mismatches, checksums]
end
private
def keg_contain?(string, keg, ignores, formula_and_runtime_deps_names = nil)
@put_string_exists_header, @put_filenames = nil
@ -186,49 +289,6 @@ module Homebrew
cellar.present? && default_cellars.exclude?(cellar)
end
def generate_sha256_line(tag, digest, cellar, tag_column, digest_column)
line = "sha256 "
tag_column += line.length
digest_column += line.length
if cellar.is_a?(Symbol)
line += "cellar: :#{cellar},"
elsif cellar_parameter_needed?(cellar)
line += %Q(cellar: "#{cellar}",)
end
line += " " * (tag_column - line.length)
line += "#{tag}:"
line += " " * (digest_column - line.length)
%Q(#{line}"#{digest}")
end
def bottle_output(bottle, root_url_using)
cellars = bottle.checksums.filter_map do |checksum|
cellar = checksum["cellar"]
next unless cellar_parameter_needed? cellar
case cellar
when String
%Q("#{cellar}")
when Symbol
":#{cellar}"
end
end
tag_column = cellars.empty? ? 0 : "cellar: #{cellars.max_by(&:length)}, ".length
tags = bottle.checksums.map { |checksum| checksum["tag"] }
# Start where the tag ends, add the max length of the tag, add two for the `: `
digest_column = tag_column + tags.max_by(&:length).length + 2
sha256_lines = bottle.checksums.map do |checksum|
generate_sha256_line(checksum["tag"], checksum["digest"], checksum["cellar"], tag_column, digest_column)
end
erb_binding = bottle.instance_eval { binding }
erb_binding.local_variable_set(:sha256_lines, sha256_lines)
erb_binding.local_variable_set(:root_url_using, root_url_using)
erb = ERB.new BOTTLE_ERB
erb.result(erb_binding).gsub(/^\s*$\n/, "")
end
def sudo_purge
return unless ENV["HOMEBREW_BOTTLE_SUDO_PURGE"]
@ -601,25 +661,6 @@ module Homebrew
json_path.write(JSON.pretty_generate(json))
end
def parse_json_files(filenames)
filenames.map do |filename|
JSON.parse(File.read(filename))
end
end
def merge_json_files(json_files)
json_files.reduce({}) do |hash, json_file|
json_file.each_value do |json_hash|
json_bottle = json_hash["bottle"]
cellar = json_bottle.delete("cellar")
json_bottle["tags"].each_value do |json_platform|
json_platform["cellar"] ||= cellar
end
end
hash.deep_merge(json_file)
end
end
def merge
bottles_hash = merge_json_files(parse_json_files(args.named))
@ -774,46 +815,6 @@ module Homebrew
end
end
def merge_bottle_spec(old_keys, old_bottle_spec, new_bottle_hash)
mismatches = []
checksums = []
new_values = {
root_url: new_bottle_hash["root_url"],
rebuild: new_bottle_hash["rebuild"],
}
skip_keys = [:sha256, :cellar]
old_keys.each do |key|
next if skip_keys.include?(key)
old_value = old_bottle_spec.send(key).to_s
new_value = new_values[key].to_s
next if old_value.present? && new_value == old_value
mismatches << "#{key}: old: #{old_value.inspect}, new: #{new_value.inspect}"
end
return [mismatches, checksums] if old_keys.exclude? :sha256
old_bottle_spec.collector.each_tag do |tag|
old_tag_spec = old_bottle_spec.collector.specification_for(tag)
old_hexdigest = old_tag_spec.checksum.hexdigest
old_cellar = old_tag_spec.cellar
new_value = new_bottle_hash.dig("tags", tag.to_s)
if new_value.present? && new_value["sha256"] != old_hexdigest
mismatches << "sha256 #{tag}: old: #{old_hexdigest.inspect}, new: #{new_value["sha256"].inspect}"
elsif new_value.present? && new_value["cellar"] != old_cellar.to_s
mismatches << "cellar #{tag}: old: #{old_cellar.to_s.inspect}, new: #{new_value["cellar"].inspect}"
else
checksums << { cellar: old_cellar, tag.to_sym => old_hexdigest }
end
end
[mismatches, checksums]
end
def old_checksums(formula, formula_ast, bottle_hash)
bottle_node = formula_ast.bottle_block
return if bottle_node.nil?

View File

@ -5,7 +5,6 @@ require "abstract_command"
require "bump_version_parser"
require "cask"
require "cask/download"
require "cli/parser"
require "utils/tar"
module Homebrew

View File

@ -4,7 +4,6 @@
require "abstract_command"
require "fileutils"
require "formula"
require "cli/parser"
require "utils/pypi"
require "utils/tar"

View File

@ -3,7 +3,6 @@
require "abstract_command"
require "formula"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -5,7 +5,6 @@ require "timeout"
require "cask/download"
require "cask/installer"
require "cask/cask_loader"
require "cli/parser"
require "system_command"
require "tap"
require "unversioned_cask_checker"

View File

@ -3,7 +3,6 @@
require "abstract_command"
require "bump_version_parser"
require "cli/parser"
require "livecheck/livecheck"
module Homebrew

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "fileutils"
module Homebrew

View File

@ -3,7 +3,6 @@
require "abstract_command"
require "commands"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "csv"
module Homebrew

View File

@ -4,7 +4,6 @@
require "formula"
require "formula_creator"
require "missing_formula"
require "cli/parser"
require "utils/pypi"
require "cask/cask_loader"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "test_runner_formula"
require "github_runner_matrix"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/github"
module Homebrew

View File

@ -3,7 +3,6 @@
require "abstract_command"
require "formula"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/git"
require "formulary"
require "software_spec"

View File

@ -3,7 +3,6 @@
require "abstract_command"
require "formula"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "cask/cask"
require "fileutils"
require "formula"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "fileutils"
require "formula"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -4,7 +4,6 @@
require "abstract_command"
require "formulary"
require "cask/cask_loader"
require "cli/parser"
class String
def f(*args)

View File

@ -4,7 +4,6 @@
require "abstract_command"
require "cache_store"
require "linkage_checker"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "formula"
require "livecheck/livecheck"
require "livecheck/strategy"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/github"
module Homebrew

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/github"
module Homebrew

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "fileutils"
require "utils/github"
require "utils/github/artifacts"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "formula"
require "github_packages"
require "github_releases"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -4,7 +4,6 @@
require "abstract_command"
require "extend/ENV"
require "formula"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -5,7 +5,6 @@ require "abstract_command"
require "json"
require "open3"
require "style"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -4,7 +4,6 @@
require "abstract_command"
require "fileutils"
require "tap"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -5,7 +5,6 @@ require "abstract_command"
require "extend/ENV"
require "sandbox"
require "timeout"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "fileutils"
require "system_command"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "fileutils"
module Homebrew

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "formula"
require "api"
require "os/mac/xcode"

View File

@ -5,7 +5,6 @@ require "abstract_command"
require "fileutils"
require "stringio"
require "formula"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/spdx"
require "system_command"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/github"
require "manpages"
require "system_command"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/pypi"
module Homebrew

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "utils/github"
require "system_command"

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
require "fileutils"
module Homebrew

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true
require "abstract_command"
require "cli/parser"
module Homebrew
module DevCmd

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/analytics"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew analytics" do
RSpec.describe Homebrew::Cmd::Analytics do
it_behaves_like "parseable arguments"
it "when HOMEBREW_NO_ANALYTICS is unset is disabled after running `brew analytics off`", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/autoremove"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew autoremove" do
RSpec.describe Homebrew::Cmd::Autoremove do
it_behaves_like "parseable arguments"
describe "integration test" do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/cleanup"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew cleanup" do
RSpec.describe Homebrew::Cmd::CleanupCmd do
before do
FileUtils.mkdir_p HOMEBREW_LIBRARY/"Homebrew/vendor/"
FileUtils.touch HOMEBREW_LIBRARY/"Homebrew/vendor/portable-ruby-version"

View File

@ -1,11 +1,9 @@
# frozen_string_literal: true
require "cmd/commands"
require "fileutils"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew commands" do
RSpec.describe Homebrew::Cmd::CommandsCmd do
it_behaves_like "parseable arguments"
it "prints a list of all available commands", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/completions"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew completions" do
RSpec.describe Homebrew::Cmd::CompletionsCmd do
it_behaves_like "parseable arguments"
it "runs the status subcommand correctly", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/config"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew config" do
RSpec.describe Homebrew::Cmd::Config do
it_behaves_like "parseable arguments"
it "prints information about the current Homebrew configuration", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/deps"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew deps" do
RSpec.describe Homebrew::Cmd::Deps do
it_behaves_like "parseable arguments"
it "outputs all of a Formula's dependencies and their dependencies on separate lines", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/desc"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew desc" do
RSpec.describe Homebrew::Cmd::Desc do
it_behaves_like "parseable arguments"
it "shows a given Formula's description", :integration_test do

View File

@ -1,7 +1,8 @@
# frozen_string_literal: true
require "cmd/developer"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew developer" do
RSpec.describe Homebrew::Cmd::Developer do
it_behaves_like "parseable arguments"
end

View File

@ -1,6 +1,11 @@
# frozen_string_literal: true
RSpec.describe "brew docs" do
require "cmd/docs"
require "cmd/shared_examples/args_parse"
RSpec.describe Homebrew::Cmd::Docs do
it_behaves_like "parseable arguments"
it "opens the docs page", :integration_test do
expect { brew "docs", "HOMEBREW_BROWSER" => "echo" }
.to output("https://docs.brew.sh\n").to_stdout

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/doctor"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew doctor" do
RSpec.describe Homebrew::Cmd::Doctor do
it_behaves_like "parseable arguments"
specify "check_integration_test", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/fetch"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew fetch" do
RSpec.describe Homebrew::Cmd::FetchCmd do
it_behaves_like "parseable arguments"
it "downloads the Formula's URL", :integration_test do

View File

@ -1,7 +1,8 @@
# frozen_string_literal: true
require "cmd/gist-logs"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew gist-logs" do
RSpec.describe Homebrew::Cmd::GistLogs do
it_behaves_like "parseable arguments"
end

View File

@ -1,6 +1,11 @@
# frozen_string_literal: true
RSpec.describe "brew", :integration_test do
require "cmd/help"
require "cmd/shared_examples/args_parse"
RSpec.describe Homebrew::Cmd::HelpCmd, :integration_test do
it_behaves_like "parseable arguments"
describe "help" do
it "prints help for a documented Ruby command" do
expect { brew "help", "cat" }

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/home"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew home" do
RSpec.describe Homebrew::Cmd::Home do
let(:testballhome_homepage) do
Formula["testballhome"].homepage
end

View File

@ -1,10 +1,9 @@
# frozen_string_literal: true
require "cmd/info"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew info" do
RSpec.describe Homebrew::Cmd::Info do
it_behaves_like "parseable arguments"
it "prints as json with the --json=v1 flag", :integration_test do
@ -25,23 +24,21 @@ RSpec.describe "brew info" do
.and be_a_success
end
describe Homebrew do
describe "::github_remote_path" do
let(:remote) { "https://github.com/Homebrew/homebrew-core" }
specify "returns correct URLs" do
expect(described_class.github_remote_path(remote, "Formula/git.rb"))
expect(described_class.new([]).github_remote_path(remote, "Formula/git.rb"))
.to eq("https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/git.rb")
expect(described_class.github_remote_path("#{remote}.git", "Formula/git.rb"))
expect(described_class.new([]).github_remote_path("#{remote}.git", "Formula/git.rb"))
.to eq("https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/git.rb")
expect(described_class.github_remote_path("git@github.com:user/repo", "foo.rb"))
expect(described_class.new([]).github_remote_path("git@github.com:user/repo", "foo.rb"))
.to eq("https://github.com/user/repo/blob/HEAD/foo.rb")
expect(described_class.github_remote_path("https://mywebsite.com", "foo/bar.rb"))
expect(described_class.new([]).github_remote_path("https://mywebsite.com", "foo/bar.rb"))
.to eq("https://mywebsite.com/foo/bar.rb")
end
end
end
end

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/install"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew install" do
RSpec.describe Homebrew::Cmd::InstallCmd do
it_behaves_like "parseable arguments"
it "installs formulae", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/leaves"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew leaves" do
RSpec.describe Homebrew::Cmd::Leaves do
it_behaves_like "parseable arguments"
context "when there are no installed Formulae", :integration_test do

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require "cmd/link"
require "cmd/shared_examples/args_parse"
RSpec.describe "brew link" do
RSpec.describe Homebrew::Cmd::Link do
it_behaves_like "parseable arguments"
it "links a given Formula", :integration_test do

View File

@ -70,7 +70,7 @@ RSpec.describe FormulaInstaller do
# rubocop:disable RSpec/NoExpectationExample
specify "basic bottle install" do
allow(DevelopmentTools).to receive(:installed?).and_return(false)
Homebrew.install_args.parse(["testball_bottle"])
Homebrew::Cmd::InstallCmd.new(["testball_bottle"])
temporarily_install_bottle(TestballBottle.new) do |f|
test_basic_formula_setup(f)
end
@ -79,7 +79,7 @@ RSpec.describe FormulaInstaller do
specify "basic bottle install with cellar information on sha256 line" do
allow(DevelopmentTools).to receive(:installed?).and_return(false)
Homebrew.install_args.parse(["testball_bottle_cellar"])
Homebrew::Cmd::InstallCmd.new(["testball_bottle_cellar"])
temporarily_install_bottle(TestballBottleCellar.new) do |f|
test_basic_formula_setup(f)