263 lines
6.5 KiB
Ruby
Raw Normal View History

2020-10-10 14:16:11 +02:00
# typed: false
# frozen_string_literal: true
2016-08-18 22:11:42 +03:00
require "optparse"
require "shellwords"
2020-08-01 02:30:46 +02:00
require "cli/parser"
2016-10-04 15:24:58 +02:00
require "extend/optparse"
require "cask/config"
2018-09-03 20:17:29 +01:00
require "cask/cmd/abstract_command"
require "cask/cmd/--cache"
2018-09-03 20:17:29 +01:00
require "cask/cmd/audit"
require "cask/cmd/cat"
require "cask/cmd/create"
require "cask/cmd/doctor"
require "cask/cmd/edit"
require "cask/cmd/fetch"
2020-04-07 08:32:30 +02:00
require "cask/cmd/help"
2018-09-03 20:17:29 +01:00
require "cask/cmd/home"
require "cask/cmd/info"
require "cask/cmd/install"
require "cask/cmd/list"
require "cask/cmd/outdated"
require "cask/cmd/reinstall"
require "cask/cmd/style"
require "cask/cmd/uninstall"
require "cask/cmd/upgrade"
require "cask/cmd/zap"
require "cask/cmd/abstract_internal_command"
require "cask/cmd/internal_help"
require "cask/cmd/internal_stanza"
2016-08-18 22:11:42 +03:00
2018-09-06 08:29:14 +02:00
module Cask
2020-08-19 10:34:07 +02:00
# Implementation of the `brew cask` command-line interface.
#
# @api private
2018-09-04 08:45:48 +01:00
class Cmd
2020-10-20 12:03:48 +02:00
extend T::Sig
include Context
2016-09-24 13:52:43 +02:00
ALIASES = {
2016-10-14 20:33:16 +02:00
"ls" => "list",
"homepage" => "home",
2020-04-07 08:32:30 +02:00
"instal" => "install", # gem does the same
"uninstal" => "uninstall",
2016-10-14 20:33:16 +02:00
"rm" => "uninstall",
"remove" => "uninstall",
"abv" => "info",
"dr" => "doctor",
}.freeze
2016-08-18 22:11:42 +03:00
DEPRECATED_COMMANDS = {
2020-11-18 08:10:21 +01:00
Cmd::Cache => "brew --cache [--cask]",
Cmd::Audit => "brew audit [--cask]",
Cmd::Cat => "brew cat [--cask]",
Cmd::Create => "brew create --cask --set-name <name> <url>",
Cmd::Doctor => "brew doctor --verbose",
2020-11-18 08:10:21 +01:00
Cmd::Edit => "brew edit [--cask]",
Cmd::Fetch => "brew fetch [--cask]",
2020-11-25 09:37:21 +00:00
Cmd::Help => "brew help",
Cmd::Home => "brew home",
2020-11-18 08:10:21 +01:00
Cmd::Info => "brew info [--cask]",
Cmd::Install => "brew install [--cask]",
Cmd::List => "brew list [--cask]",
Cmd::Outdated => "brew outdated [--cask]",
Cmd::Reinstall => "brew reinstall [--cask]",
Cmd::Style => "brew style",
Cmd::Uninstall => "brew uninstall [--cask]",
Cmd::Upgrade => "brew upgrade [--cask]",
Cmd::Zap => "brew uninstall --zap [--cask]",
}.freeze
2020-08-01 02:30:46 +02:00
def self.parser(&block)
Homebrew::CLI::Parser.new do
2020-11-16 22:18:56 +01:00
if block
2020-08-01 02:30:46 +02:00
instance_eval(&block)
else
usage_banner <<~EOS
`cask` <command> [<options>] [<cask>]
2017-05-21 00:15:56 +02:00
2020-11-25 09:37:21 +00:00
Homebrew Cask provides a friendly CLI workflow for the administration of macOS applications distributed as binaries.
See also: `man brew`
2020-08-01 02:30:46 +02:00
EOS
end
2017-05-21 00:15:56 +02:00
cask_options
2020-08-01 02:30:46 +02:00
end
end
2017-03-06 20:37:13 +01:00
2016-09-24 13:52:43 +02:00
def self.command_classes
2016-10-14 20:55:09 +02:00
@command_classes ||= constants.map(&method(:const_get))
2020-08-01 02:30:46 +02:00
.select { |klass| klass.is_a?(Class) && klass < AbstractCommand }
2017-05-20 19:08:03 +02:00
.reject(&:abstract?)
.sort_by(&:command_name)
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2016-09-24 13:52:43 +02:00
def self.commands
@commands ||= command_classes.map(&:command_name)
end
2016-08-18 22:11:42 +03:00
2017-05-21 00:15:56 +02:00
def self.lookup_command(command_name)
2016-09-24 13:52:43 +02:00
@lookup ||= Hash[commands.zip(command_classes)]
2017-05-21 00:15:56 +02:00
command_name = ALIASES.fetch(command_name, command_name)
2020-04-07 08:32:30 +02:00
@lookup.fetch(command_name, nil)
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2020-07-20 13:18:09 -04:00
def self.aliases
ALIASES
end
2020-04-07 08:32:30 +02:00
def self.run(*args)
new(*args).run
end
2020-04-07 08:32:30 +02:00
def initialize(*args)
2020-08-01 02:30:46 +02:00
@argv = args
2020-04-07 08:32:30 +02:00
end
2020-04-07 08:32:30 +02:00
def find_external_command(command)
@tap_cmd_directories ||= Tap.cmd_directories
@path ||= PATH.new(@tap_cmd_directories, ENV["HOMEBREW_PATH"])
2020-04-07 08:32:30 +02:00
external_ruby_cmd = @tap_cmd_directories.map { |d| d/"brewcask-#{command}.rb" }
.find(&:file?)
external_ruby_cmd ||= which("brewcask-#{command}.rb", @path)
if external_ruby_cmd
2020-04-07 08:32:30 +02:00
ExternalRubyCommand.new(command, external_ruby_cmd)
elsif external_command = which("brewcask-#{command}", @path)
ExternalCommand.new(external_command)
2016-08-18 22:11:42 +03:00
end
end
2020-04-07 08:32:30 +02:00
def detect_internal_command(*args)
args.each_with_index do |arg, i|
if command = self.class.lookup_command(arg)
args.delete_at(i)
return [command, args]
elsif !arg.start_with?("-")
break
end
end
2017-05-21 00:15:56 +02:00
2020-04-07 08:32:30 +02:00
nil
2017-05-21 00:15:56 +02:00
end
2020-04-07 08:32:30 +02:00
def detect_external_command(*args)
args.each_with_index do |arg, i|
if command = find_external_command(arg)
args.delete_at(i)
return [command, args]
elsif !arg.start_with?("-")
break
end
end
2020-04-07 08:32:30 +02:00
nil
end
2017-05-21 00:15:56 +02:00
def run
2020-08-01 02:30:46 +02:00
argv = @argv
2016-08-18 22:11:42 +03:00
2020-08-01 02:30:46 +02:00
args = self.class.parser.parse(argv, ignore_invalid_options: true)
2016-08-18 22:11:42 +03:00
Tap.install_default_cask_tap_if_necessary
2020-08-01 02:30:46 +02:00
command, argv = detect_internal_command(*argv) ||
detect_external_command(*argv) ||
[args.remaining.empty? ? NullCommand : UnknownSubcommand.new(args.remaining.first), argv]
if (replacement = DEPRECATED_COMMANDS[command])
odisabled "`brew cask #{command.command_name}`", replacement
end
2020-08-01 02:30:46 +02:00
if args.help?
puts command.help
else
command.run(*argv)
2016-08-18 22:11:42 +03:00
end
2020-08-01 02:30:46 +02:00
rescue CaskError, MethodDeprecatedError, ArgumentError => e
onoe e.message
$stderr.puts e.backtrace if args.debug?
exit 1
2016-08-18 22:11:42 +03:00
end
2020-08-19 10:34:07 +02:00
# Wrapper class for running an external Ruby command.
2020-04-07 08:32:30 +02:00
class ExternalRubyCommand
def initialize(command, path)
@command_name = command.to_s.capitalize.to_sym
@path = path
2016-09-24 13:52:43 +02:00
end
2020-04-07 08:32:30 +02:00
def run(*args)
command_class&.run(*args)
end
def help
command_class&.help
end
private
def command_class
return @command_class if defined?(@command_class)
2020-04-07 08:32:30 +02:00
require @path
@command_class = begin
2020-04-07 08:32:30 +02:00
Cmd.const_get(@command_name)
rescue NameError
nil
end
2016-08-18 22:11:42 +03:00
end
2020-04-07 08:32:30 +02:00
end
2016-08-18 22:11:42 +03:00
2020-08-19 10:34:07 +02:00
# Wrapper class for running an external command.
2020-04-07 08:32:30 +02:00
class ExternalCommand
def initialize(path)
@path = path
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2020-08-01 02:30:46 +02:00
def run(*argv)
exec @path, *argv
2016-08-18 22:11:42 +03:00
end
def help
exec @path, "--help"
end
2020-04-07 08:32:30 +02:00
end
2016-08-18 22:11:42 +03:00
2020-08-19 10:34:07 +02:00
# Helper class for showing help for unknown subcommands.
2020-08-01 02:30:46 +02:00
class UnknownSubcommand
def initialize(command_name)
@command_name = command_name
end
2016-08-18 22:11:42 +03:00
2020-08-01 02:30:46 +02:00
def run(*)
raise UsageError, "Subcommand `#{@command_name}` does not exist."
2016-09-24 13:52:43 +02:00
end
def help
run
end
2016-08-18 22:11:42 +03:00
end
2020-08-01 02:30:46 +02:00
2020-08-19 10:34:07 +02:00
# Helper class for showing help when no subcommand is given.
2020-08-01 02:30:46 +02:00
class NullCommand
def self.run(*)
raise UsageError, "No subcommand given."
end
def self.help
Cmd.parser.generate_help_text
end
end
2016-08-18 22:11:42 +03:00
end
end