2020-10-10 14:16:11 +02:00
|
|
|
# typed: false
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-09-28 00:48:19 +02:00
|
|
|
require "locale"
|
2018-07-30 21:07:36 +02:00
|
|
|
require "lazy_object"
|
2016-08-18 22:11:42 +03:00
|
|
|
|
2018-09-03 19:39:07 +01:00
|
|
|
require "cask/artifact"
|
2017-04-06 00:33:31 +02:00
|
|
|
|
2018-09-03 19:39:07 +01:00
|
|
|
require "cask/caskroom"
|
|
|
|
require "cask/exceptions"
|
2018-06-09 12:20:58 +02:00
|
|
|
|
2018-09-03 19:39:07 +01:00
|
|
|
require "cask/dsl/appcast"
|
|
|
|
require "cask/dsl/base"
|
|
|
|
require "cask/dsl/caveats"
|
|
|
|
require "cask/dsl/conflicts_with"
|
|
|
|
require "cask/dsl/container"
|
|
|
|
require "cask/dsl/depends_on"
|
|
|
|
require "cask/dsl/postflight"
|
|
|
|
require "cask/dsl/preflight"
|
|
|
|
require "cask/dsl/uninstall_postflight"
|
|
|
|
require "cask/dsl/uninstall_preflight"
|
|
|
|
require "cask/dsl/version"
|
2016-08-18 22:11:42 +03:00
|
|
|
|
2018-09-03 19:39:07 +01:00
|
|
|
require "cask/url"
|
2020-08-01 02:30:46 +02:00
|
|
|
require "cask/utils"
|
2018-06-09 12:20:58 +02:00
|
|
|
|
2018-09-06 08:29:14 +02:00
|
|
|
module Cask
|
2020-08-24 23:09:43 +02:00
|
|
|
# Class representing the domain-specific language used for casks.
|
|
|
|
#
|
|
|
|
# @api private
|
2016-09-24 13:52:43 +02:00
|
|
|
class DSL
|
2017-04-06 00:33:31 +02:00
|
|
|
ORDINARY_ARTIFACT_CLASSES = [
|
|
|
|
Artifact::Installer,
|
|
|
|
Artifact::App,
|
|
|
|
Artifact::Artifact,
|
|
|
|
Artifact::AudioUnitPlugin,
|
|
|
|
Artifact::Binary,
|
|
|
|
Artifact::Colorpicker,
|
|
|
|
Artifact::Dictionary,
|
|
|
|
Artifact::Font,
|
|
|
|
Artifact::InputMethod,
|
|
|
|
Artifact::InternetPlugin,
|
2019-10-23 16:28:00 +03:00
|
|
|
Artifact::Manpage,
|
2017-04-06 00:33:31 +02:00
|
|
|
Artifact::Pkg,
|
|
|
|
Artifact::Prefpane,
|
|
|
|
Artifact::Qlplugin,
|
2020-04-05 15:30:37 +02:00
|
|
|
Artifact::Mdimporter,
|
2017-04-06 00:33:31 +02:00
|
|
|
Artifact::ScreenSaver,
|
|
|
|
Artifact::Service,
|
|
|
|
Artifact::StageOnly,
|
|
|
|
Artifact::Suite,
|
|
|
|
Artifact::VstPlugin,
|
|
|
|
Artifact::Vst3Plugin,
|
|
|
|
Artifact::Uninstall,
|
|
|
|
Artifact::Zap,
|
2016-10-14 20:33:16 +02:00
|
|
|
].freeze
|
2016-09-24 13:52:43 +02:00
|
|
|
|
2019-04-19 21:46:20 +09:00
|
|
|
ACTIVATABLE_ARTIFACT_CLASSES = (ORDINARY_ARTIFACT_CLASSES - [Artifact::StageOnly]).freeze
|
2016-09-24 13:52:43 +02:00
|
|
|
|
2017-04-06 00:33:31 +02:00
|
|
|
ARTIFACT_BLOCK_CLASSES = [
|
|
|
|
Artifact::PreflightBlock,
|
|
|
|
Artifact::PostflightBlock,
|
2016-10-14 20:33:16 +02:00
|
|
|
].freeze
|
2016-08-18 22:11:42 +03:00
|
|
|
|
2019-04-19 21:46:20 +09:00
|
|
|
DSL_METHODS = Set.new([
|
|
|
|
:appcast,
|
|
|
|
:artifacts,
|
|
|
|
:auto_updates,
|
|
|
|
:caveats,
|
|
|
|
:conflicts_with,
|
|
|
|
:container,
|
2020-07-29 15:40:31 +01:00
|
|
|
:desc,
|
2019-04-19 21:46:20 +09:00
|
|
|
:depends_on,
|
|
|
|
:homepage,
|
|
|
|
:language,
|
|
|
|
:languages,
|
|
|
|
:name,
|
|
|
|
:sha256,
|
|
|
|
:staged_path,
|
|
|
|
:url,
|
|
|
|
:version,
|
|
|
|
:appdir,
|
|
|
|
*ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
|
|
|
|
*ACTIVATABLE_ARTIFACT_CLASSES.map(&:dsl_key),
|
|
|
|
*ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },
|
|
|
|
]).freeze
|
2016-09-24 13:52:43 +02:00
|
|
|
|
2017-10-04 15:47:53 +02:00
|
|
|
attr_reader :cask, :token
|
|
|
|
|
2017-04-06 00:33:31 +02:00
|
|
|
def initialize(cask)
|
|
|
|
@cask = cask
|
|
|
|
@token = cask.token
|
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 name(*args)
|
|
|
|
@name ||= []
|
|
|
|
return @name if args.empty?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
@name.concat(args.flatten)
|
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
|
2020-07-29 15:40:31 +01:00
|
|
|
def desc(description = nil)
|
|
|
|
set_unique_stanza(:desc, description.nil?) { description }
|
|
|
|
end
|
|
|
|
|
2017-07-30 16:26:44 +02:00
|
|
|
def set_unique_stanza(stanza, should_return)
|
|
|
|
return instance_variable_get("@#{stanza}") if should_return
|
|
|
|
|
|
|
|
if instance_variable_defined?("@#{stanza}")
|
2017-04-06 00:33:31 +02:00
|
|
|
raise CaskInvalidError.new(cask, "'#{stanza}' stanza may only appear once.")
|
2017-07-30 16:26:44 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
instance_variable_set("@#{stanza}", yield)
|
2017-04-06 00:33:31 +02:00
|
|
|
rescue CaskInvalidError
|
|
|
|
raise
|
2018-09-02 20:14:54 +01:00
|
|
|
rescue => e
|
2017-04-06 00:33:31 +02:00
|
|
|
raise CaskInvalidError.new(cask, "'#{stanza}' stanza failed with: #{e}")
|
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 homepage(homepage = nil)
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:homepage, homepage.nil?) { homepage }
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2016-09-28 00:48:19 +02:00
|
|
|
def language(*args, default: false, &block)
|
2017-09-23 01:40:14 +02:00
|
|
|
if args.empty?
|
|
|
|
language_eval
|
|
|
|
elsif block_given?
|
2016-09-25 22:13:44 +02:00
|
|
|
@language_blocks ||= {}
|
|
|
|
@language_blocks[args] = block
|
2016-09-28 00:57:19 +02:00
|
|
|
|
|
|
|
return unless default
|
|
|
|
|
|
|
|
unless @language_blocks.default.nil?
|
2017-04-06 00:33:31 +02:00
|
|
|
raise CaskInvalidError.new(cask, "Only one default language may be defined.")
|
2016-09-28 00:57:19 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
@language_blocks.default = block
|
2016-09-14 23:11:21 +02:00
|
|
|
else
|
2017-09-23 01:40:14 +02:00
|
|
|
raise CaskInvalidError.new(cask, "No block given to language stanza.")
|
2016-09-14 23:11:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-09-18 04:15:28 +02:00
|
|
|
def language_eval
|
2020-08-12 00:04:20 +02:00
|
|
|
return @language if defined?(@language)
|
2016-09-25 22:13:44 +02:00
|
|
|
|
2017-05-29 18:24:52 +01:00
|
|
|
return @language = nil if @language_blocks.nil? || @language_blocks.empty?
|
2016-09-25 22:13:44 +02:00
|
|
|
|
2019-02-19 13:11:32 +00:00
|
|
|
raise CaskInvalidError.new(cask, "No default language specified.") if @language_blocks.default.nil?
|
2017-09-23 01:40:14 +02:00
|
|
|
|
2020-07-21 21:28:58 +02:00
|
|
|
locales = cask.config.languages
|
|
|
|
.map do |language|
|
2020-07-22 00:50:27 +02:00
|
|
|
Locale.parse(language)
|
|
|
|
rescue Locale::ParserError
|
|
|
|
nil
|
|
|
|
end
|
2020-07-21 21:28:58 +02:00
|
|
|
.compact
|
2018-08-19 22:10:20 +02:00
|
|
|
|
|
|
|
locales.each do |locale|
|
2018-05-28 15:01:58 +01:00
|
|
|
key = locale.detect(@language_blocks.keys)
|
2016-09-28 00:48:19 +02:00
|
|
|
|
2016-10-03 02:34:32 +02:00
|
|
|
next if key.nil?
|
|
|
|
|
|
|
|
return @language = @language_blocks[key].call
|
|
|
|
end
|
2016-09-25 22:13:44 +02:00
|
|
|
|
2016-09-28 00:48:19 +02:00
|
|
|
@language = @language_blocks.default.call
|
2016-09-18 04:15:28 +02:00
|
|
|
end
|
|
|
|
|
2017-09-27 00:17:47 -07:00
|
|
|
def languages
|
|
|
|
return [] if @language_blocks.nil?
|
|
|
|
|
|
|
|
@language_blocks.keys.flatten
|
|
|
|
end
|
|
|
|
|
2018-07-30 21:07:36 +02:00
|
|
|
def url(*args)
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:url, args.empty? && !block_given?) do
|
2018-07-30 21:07:36 +02:00
|
|
|
if block_given?
|
|
|
|
LazyObject.new { URL.new(*yield) }
|
|
|
|
else
|
|
|
|
URL.new(*args)
|
2017-07-30 16:26:44 +02:00
|
|
|
end
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
def appcast(*args)
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:appcast, args.empty?) { DSL::Appcast.new(*args) }
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
def container(*args)
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:container, args.empty?) do
|
2018-07-23 23:04:49 +02:00
|
|
|
DSL::Container.new(*args)
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
def version(arg = nil)
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:version, arg.nil?) do
|
|
|
|
if !arg.is_a?(String) && arg != :latest
|
2017-04-06 00:33:31 +02:00
|
|
|
raise CaskInvalidError.new(cask, "invalid 'version' value: '#{arg.inspect}'")
|
2017-07-30 16:26:44 +02:00
|
|
|
end
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2017-07-30 16:26:44 +02:00
|
|
|
DSL::Version.new(arg)
|
|
|
|
end
|
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 sha256(arg = nil)
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:sha256, arg.nil?) do
|
|
|
|
if !arg.is_a?(String) && arg != :no_check
|
2017-04-06 00:33:31 +02:00
|
|
|
raise CaskInvalidError.new(cask, "invalid 'sha256' value: '#{arg.inspect}'")
|
2017-07-30 16:26:44 +02:00
|
|
|
end
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2017-07-30 16:26:44 +02:00
|
|
|
arg
|
|
|
|
end
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# `depends_on` uses a load method so that multiple stanzas can be merged.
|
2016-09-24 13:52:43 +02:00
|
|
|
def depends_on(*args)
|
|
|
|
@depends_on ||= DSL::DependsOn.new
|
2017-06-28 17:53:59 +02:00
|
|
|
return @depends_on if args.empty?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
begin
|
2017-06-28 17:53:59 +02:00
|
|
|
@depends_on.load(*args)
|
2016-09-24 13:52:43 +02:00
|
|
|
rescue RuntimeError => e
|
2017-04-06 00:33:31 +02:00
|
|
|
raise CaskInvalidError.new(cask, e)
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
|
|
|
@depends_on
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
def conflicts_with(*args)
|
|
|
|
# TODO: remove this constraint, and instead merge multiple conflicts_with stanzas
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:conflicts_with, args.empty?) { DSL::ConflictsWith.new(*args) }
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
def artifacts
|
2017-10-04 17:08:35 +02:00
|
|
|
@artifacts ||= SortedSet.new
|
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 caskroom_path
|
2020-07-21 21:28:58 +02:00
|
|
|
cask.caskroom_path
|
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 staged_path
|
|
|
|
return @staged_path if @staged_path
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
cask_version = version || :unknown
|
|
|
|
@staged_path = caskroom_path.join(cask_version.to_s)
|
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
|
2017-11-24 17:44:01 +01:00
|
|
|
def caveats(*strings, &block)
|
|
|
|
@caveats ||= DSL::Caveats.new(cask)
|
2016-09-24 13:52:43 +02:00
|
|
|
if block_given?
|
2017-11-24 17:44:01 +01:00
|
|
|
@caveats.eval_caveats(&block)
|
|
|
|
elsif strings.any?
|
|
|
|
strings.each do |string|
|
|
|
|
@caveats.eval_caveats { string }
|
|
|
|
end
|
|
|
|
else
|
|
|
|
return @caveats.to_s
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
|
|
|
@caveats
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
def auto_updates(auto_updates = nil)
|
2017-07-30 16:26:44 +02:00
|
|
|
set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
|
2017-04-06 00:33:31 +02:00
|
|
|
ORDINARY_ARTIFACT_CLASSES.each do |klass|
|
2017-10-04 15:47:53 +02:00
|
|
|
define_method(klass.dsl_key) do |*args|
|
2019-10-13 10:03:26 +01:00
|
|
|
if [*artifacts.map(&:class), klass].include?(Artifact::StageOnly) &&
|
|
|
|
(artifacts.map(&:class) & ACTIVATABLE_ARTIFACT_CLASSES).any?
|
|
|
|
raise CaskInvalidError.new(cask, "'stage_only' must be the only activatable artifact.")
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
2019-10-13 10:03:26 +01:00
|
|
|
|
|
|
|
artifacts.add(klass.from_args(cask, *args))
|
|
|
|
rescue CaskInvalidError
|
|
|
|
raise
|
|
|
|
rescue => e
|
|
|
|
raise CaskInvalidError.new(cask, "invalid '#{klass.dsl_key}' stanza: #{e}")
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-06 00:33:31 +02:00
|
|
|
ARTIFACT_BLOCK_CLASSES.each do |klass|
|
|
|
|
[klass.dsl_key, klass.uninstall_dsl_key].each do |dsl_key|
|
|
|
|
define_method(dsl_key) do |&block|
|
2017-10-04 17:08:35 +02:00
|
|
|
artifacts.add(klass.new(cask, dsl_key => block))
|
2017-04-06 00:33:31 +02:00
|
|
|
end
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# No need to define it as it's the default/superclass implementation.
|
2020-09-01 14:05:52 +01:00
|
|
|
# rubocop:disable Style/MissingRespondToMissing
|
2016-09-24 13:52:43 +02:00
|
|
|
def method_missing(method, *)
|
|
|
|
if method
|
|
|
|
Utils.method_missing_message(method, token)
|
|
|
|
nil
|
|
|
|
else
|
|
|
|
super
|
|
|
|
end
|
2016-09-20 15:11:33 +02:00
|
|
|
end
|
2020-09-01 14:05:52 +01:00
|
|
|
# rubocop:enable Style/MissingRespondToMissing
|
2016-09-20 15:11:33 +02:00
|
|
|
|
2016-09-24 13:52:43 +02:00
|
|
|
def appdir
|
2017-12-03 21:21:31 +01:00
|
|
|
cask.config.appdir
|
2016-09-24 13:52:43 +02:00
|
|
|
end
|
2016-08-18 22:11:42 +03:00
|
|
|
end
|
|
|
|
end
|