Newer
Older
require "hbc/cli/audit"
require "hbc/cli/cat"
require "hbc/cli/cleanup"
require "hbc/cli/create"
require "hbc/cli/doctor"
require "hbc/cli/edit"
require "hbc/cli/fetch"
require "hbc/cli/home"
require "hbc/cli/info"
require "hbc/cli/install"
require "hbc/cli/list"
require "hbc/cli/search"
require "hbc/cli/style"
require "hbc/cli/uninstall"
require "hbc/cli/--version"
require "hbc/cli/abstract_internal_command"
require "hbc/cli/internal_appcast_checkpoint"
require "hbc/cli/internal_checkurl"
require "hbc/cli/internal_dump"
require "hbc/cli/internal_help"
require "hbc/cli/internal_stanza"
module Hbc
class CLI
ALIASES = {
"ls" => "list",
"homepage" => "home",
"-S" => "search", # verb starting with "-" is questionable
"up" => "update",
"instal" => "install", # gem does the same
"rm" => "uninstall",
"remove" => "uninstall",
"abv" => "info",
"dr" => "doctor",
}.freeze
include Options
option "--appdir=PATH", ->(value) { Hbc.appdir = value }
option "--colorpickerdir=PATH", ->(value) { Hbc.colorpickerdir = value }
option "--prefpanedir=PATH", ->(value) { Hbc.prefpanedir = value }
option "--qlplugindir=PATH", ->(value) { Hbc.qlplugindir = value }
option "--dictionarydir=PATH", ->(value) { Hbc.dictionarydir = value }
option "--fontdir=PATH", ->(value) { Hbc.fontdir = value }
option "--servicedir=PATH", ->(value) { Hbc.servicedir = value }
option "--input_methoddir=PATH", ->(value) { Hbc.input_methoddir = value }
option "--internet_plugindir=PATH", ->(value) { Hbc.internet_plugindir = value }
option "--audio_unit_plugindir=PATH", ->(value) { Hbc.audio_unit_plugindir = value }
option "--vst_plugindir=PATH", ->(value) { Hbc.vst_plugindir = value }
option "--vst3_plugindir=PATH", ->(value) { Hbc.vst3_plugindir = value }
option "--screen_saverdir=PATH", ->(value) { Hbc.screen_saverdir = value }
option "--help", :help, false
# handled in OS::Mac
option "--language a,b,c", ->(*) { raise OptionParser::InvalidOption }
# override default handling of --version
option "--version", ->(*) { raise OptionParser::InvalidOption }
@command_classes ||= constants.map(&method(:const_get))
.select { |klass| klass.respond_to?(:run) }
.reject(&:abstract?)
.sort_by(&:command_name)
def self.commands
@commands ||= command_classes.map(&:command_name)
end
@lookup ||= Hash[commands.zip(command_classes)]
command_name = ALIASES.fetch(command_name, command_name)
@lookup.fetch(command_name, command_name)
command.is_a?(Class) && !command.abstract? && command.needs_init?
def self.run_command(command, *rest)
if command.respond_to?(:run)
# usual case: built-in command verb
command.run(*rest)
elsif require?(which("brewcask-#{command}.rb"))
# external command as Ruby library on PATH, Homebrew-style
elsif command.to_s.include?("/") && require?(command.to_s)
# external command as Ruby library with literal path, useful
# for development and troubleshooting
sym = File.basename(command.to_s, ".rb").capitalize
if klass.respond_to?(:run)
# invoke "run" on a Ruby library which follows our coding conventions
# other Ruby libraries must do everything via "require"
klass.run(*rest)
end
# arbitrary external executable on PATH, Homebrew-style
exec "brewcask-#{command}", *ARGV[1..-1]
elsif Pathname.new(command.to_s).executable? &&
command.to_s.include?("/") &&
# arbitrary external executable with literal path, useful
# for development and troubleshooting
exec command, *ARGV[1..-1]
else
# failure
NullCommand.new(command).run
def self.run(*args)
new(*args).run
end
def initialize(*args)
@args = process_options(*args)
end
def run
command_name, *args = *@args
command = help? ? "help" : self.class.lookup_command(command_name)
MacOS.full_version = ENV["MACOS_VERSION"] unless ENV["MACOS_VERSION"].nil?
Hbc.default_tap.install unless Hbc.default_tap.installed?
Hbc.init if self.class.should_init?(command)
self.class.run_command(command, *args)
rescue CaskError, CaskSha256MismatchError, ArgumentError, OptionParser::InvalidOption => e
msg << e.backtrace.join("\n") if ARGV.debug?
onoe msg
exit 1
rescue StandardError, ScriptError, NoMemoryError => e
msg = "#{e.message}\n"
msg << Utils.error_message_with_suggestions
msg << e.backtrace.join("\n")
onoe msg
exit 1
def self.nice_listing(cask_list)
cask_taps = {}
cask_list.each do |c|
user, repo, token = c.split "/"
cask_taps[token] ||= []
cask_taps[token].push "#{user}/#{repo}"
list = []
cask_taps.each do |token, taps|
if taps.length == 1
list.push token
else
taps.each { |r| list.push [r, token].join "/" }
end
end
list.sort
def process_options(*args)
all_args = Shellwords.shellsplit(ENV["HOMEBREW_CASK_OPTS"] || "") + args
if idx = all_args.index("--")
non_options += all_args.drop(idx)
all_args = all_args.first(idx)
!process_arguments([arg]).empty?
rescue OptionParser::InvalidOption, OptionParser::MissingArgument, OptionParser::AmbiguousOption
true
class NullCommand
def initialize(attempted_verb)
@attempted_verb = attempted_verb
end
def run(*_args)
purpose
usage
return if @attempted_verb.to_s.strip.empty?
return if @attempted_verb == "help"
raise ArgumentError, "Unknown command: #{@attempted_verb}"
def purpose
puts <<-EOS.undent
brew-cask provides a friendly homebrew-style CLI workflow for the
administration of macOS applications distributed as binaries.
def usage
max_command_len = CLI.commands.map(&:length).max
puts "Commands:\n\n"
CLI.command_classes.each do |klass|
next unless klass.visible
puts " #{klass.command_name.ljust(max_command_len)} #{_help_for(klass)}"
end
puts %Q(\nSee also "man brew-cask")
def _help_for(klass)
klass.respond_to?(:help) ? klass.help : nil
end