Skip to content

Commit

Permalink
Merge pull request #16975 from Homebrew/ported-cmds
Browse files Browse the repository at this point in the history
Begin porting non-dev commands to use AbstractCommand
  • Loading branch information
MikeMcQuaid committed Mar 31, 2024
2 parents da456da + 7f78fed commit 21dd3c2
Show file tree
Hide file tree
Showing 85 changed files with 2,031 additions and 2,054 deletions.
3 changes: 3 additions & 0 deletions Library/Homebrew/abstract_command.rb
Original file line number Diff line number Diff line change
@@ -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`.
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def fixopt(formula)
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)
Expand Down
73 changes: 35 additions & 38 deletions Library/Homebrew/cmd/analytics.rb
Original file line number Diff line number Diff line change
@@ -1,51 +1,48 @@
# typed: strict
# frozen_string_literal: true

require "cli/parser"
require "abstract_command"

module Homebrew
module_function
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>.
sig { returns(CLI::Parser) }
def analytics_args
Homebrew::CLI::Parser.new do
description <<~EOS
Control Homebrew's anonymous aggregate user behaviour analytics.
Read more at <https://docs.brew.sh/Analytics>.
`brew analytics` [`state`]:
Display the current state of Homebrew's analytics.
`brew analytics` [`state`]:
Display the current state of Homebrew's analytics.
`brew analytics` (`on`|`off`):
Turn Homebrew's analytics on or off respectively.
EOS

`brew analytics` (`on`|`off`):
Turn Homebrew's analytics on or off respectively.
EOS

named_args %w[state on off regenerate-uuid], max: 1
end
end

sig { void }
def analytics
args = analytics_args.parse
named_args %w[state on off regenerate-uuid], max: 1
end

case args.named.first
when nil, "state"
if Utils::Analytics.disabled?
puts "InfluxDB analytics are disabled."
else
puts "InfluxDB analytics are enabled."
sig { override.void }
def run
case args.named.first
when nil, "state"
if Utils::Analytics.disabled?
puts "InfluxDB analytics are disabled."
else
puts "InfluxDB analytics are enabled."
end
puts "Google Analytics were destroyed."
when "on"
Utils::Analytics.enable!
when "off"
Utils::Analytics.disable!
when "regenerate-uuid"
Utils::Analytics.delete_uuid!
opoo "Homebrew no longer uses an analytics UUID so this has been deleted!"
puts "brew analytics regenerate-uuid is no longer necessary."
else
raise UsageError, "unknown subcommand: #{args.named.first}"
end
end
puts "Google Analytics were destroyed."
when "on"
Utils::Analytics.enable!
when "off"
Utils::Analytics.disable!
when "regenerate-uuid"
Utils::Analytics.delete_uuid!
opoo "Homebrew no longer uses an analytics UUID so this has been deleted!"
puts "brew analytics regenerate-uuid is no longer necessary."
else
raise UsageError, "unknown subcommand: #{args.named.first}"
end
end
end
33 changes: 16 additions & 17 deletions Library/Homebrew/cmd/autoremove.rb
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
# 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
description <<~EOS
Uninstall formulae that were only installed as a dependency of another formula and are now no longer needed.
EOS
switch "-n", "--dry-run",
description: "List what would be uninstalled, but do not actually uninstall anything."
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
switch "-n", "--dry-run",
description: "List what would be uninstalled, but do not actually uninstall anything."

named_args :none
end
end
named_args :none
end

sig { void }
def self.autoremove
args = autoremove_args.parse

Cleanup.autoremove(dry_run: args.dry_run?)
sig { override.void }
def run
Cleanup.autoremove(dry_run: args.dry_run?)
end
end
end
end
113 changes: 55 additions & 58 deletions Library/Homebrew/cmd/cleanup.rb
Original file line number Diff line number Diff line change
@@ -1,75 +1,72 @@
# typed: strict
# frozen_string_literal: true

require "abstract_command"
require "cleanup"
require "cli/parser"

module Homebrew
module_function
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,
and remove old versions of installed formulae. If arguments are specified,
only do this for the given formulae and casks. Removes all downloads more than
#{days} days old. This can be adjusted with `HOMEBREW_CLEANUP_MAX_AGE_DAYS`.
EOS
flag "--prune=",
description: "Remove all cache files older than specified <days>. " \
"If you want to remove everything, use `--prune=all`."
switch "-n", "--dry-run",
description: "Show what would be removed, but do not actually remove anything."
switch "-s",
description: "Scrub the cache, including downloads for even the latest versions. " \
"Note that downloads for any installed formulae or casks will still not be deleted. " \
"If you want to delete those too: `rm -rf \"$(brew --cache)\"`"
switch "--prune-prefix",
description: "Only prune the symlinks and directories from the prefix and remove no other files."

sig { returns(CLI::Parser) }
def cleanup_args
Homebrew::CLI::Parser.new 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,
and remove old versions of installed formulae. If arguments are specified,
only do this for the given formulae and casks. Removes all downloads more than
#{days} days old. This can be adjusted with `HOMEBREW_CLEANUP_MAX_AGE_DAYS`.
EOS
flag "--prune=",
description: "Remove all cache files older than specified <days>. " \
"If you want to remove everything, use `--prune=all`."
switch "-n", "--dry-run",
description: "Show what would be removed, but do not actually remove anything."
switch "-s",
description: "Scrub the cache, including downloads for even the latest versions. " \
"Note that downloads for any installed formulae or casks will still not be deleted. " \
"If you want to delete those too: `rm -rf \"$(brew --cache)\"`"
switch "--prune-prefix",
description: "Only prune the symlinks and directories from the prefix and remove no other files."
named_args [:formula, :cask]
end

named_args [:formula, :cask]
end
end
sig { override.void }
def run
days = args.prune.presence&.then do |prune|
case prune
when /\A\d+\Z/
prune.to_i
when "all"
0
else
raise UsageError, "`--prune` expects an integer or `all`."
end
end

sig { void }
def cleanup
args = cleanup_args.parse
cleanup = Cleanup.new(*args.named, dry_run: args.dry_run?, scrub: args.s?, days:)
if args.prune_prefix?
cleanup.prune_prefix_symlinks_and_directories
return
end

days = args.prune.presence&.then do |prune|
case prune
when /\A\d+\Z/
prune.to_i
when "all"
0
else
raise UsageError, "`--prune` expects an integer or `all`."
end
end
cleanup.clean!(quiet: args.quiet?, periodic: false)

cleanup = Cleanup.new(*args.named, dry_run: args.dry_run?, scrub: args.s?, days:)
if args.prune_prefix?
cleanup.prune_prefix_symlinks_and_directories
return
end
unless cleanup.disk_cleanup_size.zero?
disk_space = disk_usage_readable(cleanup.disk_cleanup_size)
if args.dry_run?
ohai "This operation would free approximately #{disk_space} of disk space."
else
ohai "This operation has freed approximately #{disk_space} of disk space."
end
end

cleanup.clean!(quiet: args.quiet?, periodic: false)
return if cleanup.unremovable_kegs.empty?

unless cleanup.disk_cleanup_size.zero?
disk_space = disk_usage_readable(cleanup.disk_cleanup_size)
if args.dry_run?
ohai "This operation would free approximately #{disk_space} of disk space."
else
ohai "This operation has freed approximately #{disk_space} of disk space."
ofail <<~EOS
Could not cleanup old kegs! Fix your permissions on:
#{cleanup.unremovable_kegs.join "\n "}
EOS
end
end

return if cleanup.unremovable_kegs.empty?

ofail <<~EOS
Could not cleanup old kegs! Fix your permissions on:
#{cleanup.unremovable_kegs.join "\n "}
EOS
end
end
79 changes: 38 additions & 41 deletions Library/Homebrew/cmd/commands.rb
Original file line number Diff line number Diff line change
@@ -1,49 +1,46 @@
# 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
description <<~EOS
Show lists of built-in and external commands.
EOS
switch "-q", "--quiet",
description: "List only the names of commands without category headers."
switch "--include-aliases",
depends_on: "--quiet",
description: "Include aliases of internal commands."

named_args :none
end
end

sig { void }
def commands
args = commands_args.parse

if args.quiet?
puts Formatter.columns(Commands.commands(aliases: args.include_aliases?))
return
end

prepend_separator = T.let(false, T::Boolean)

{
"Built-in commands" => Commands.internal_commands,
"Built-in developer commands" => Commands.internal_developer_commands,
"External commands" => Commands.external_commands,
}.each do |title, commands|
next if commands.blank?

puts if prepend_separator
ohai title, Formatter.columns(commands)

prepend_separator ||= true
module Cmd
class CommandsCmd < AbstractCommand
cmd_args do
description <<~EOS
Show lists of built-in and external commands.
EOS
switch "-q", "--quiet",
description: "List only the names of commands without category headers."
switch "--include-aliases",
depends_on: "--quiet",
description: "Include aliases of internal commands."

named_args :none
end

sig { override.void }
def run
if args.quiet?
puts Formatter.columns(Commands.commands(aliases: args.include_aliases?))
return
end

prepend_separator = T.let(false, T::Boolean)

{
"Built-in commands" => Commands.internal_commands,
"Built-in developer commands" => Commands.internal_developer_commands,
"External commands" => Commands.external_commands,
}.each do |title, commands|
next if commands.blank?

puts if prepend_separator
ohai title, Formatter.columns(commands)

prepend_separator ||= true
end
end
end
end
end

0 comments on commit 21dd3c2

Please sign in to comment.