brew/Library/Homebrew/cask/lib/hbc/cask_loader.rb

219 lines
5.1 KiB
Ruby
Raw Normal View History

2018-03-07 16:14:55 +00:00
require "uri"
2016-10-08 13:25:38 +02:00
module Hbc
module CaskLoader
class FromContentLoader
2017-06-28 09:25:14 +02:00
attr_reader :content
2017-10-08 15:20:58 +02:00
def self.can_load?(ref)
return false unless ref.respond_to?(:to_str)
content = ref.to_str
token = /(?:"[^"]*"|'[^']*')/
curly = /\(\s*#{token}\s*\)\s*\{.*\}/
do_end = /\s+#{token}\s+do(?:\s*;\s*|\s+).*end/
regex = /\A\s*cask(?:#{curly.source}|#{do_end.source})\s*\Z/m
content.match?(regex)
end
def initialize(content)
@content = content.force_encoding("UTF-8")
end
def load
instance_eval(content, __FILE__, __LINE__)
end
2016-10-08 13:25:38 +02:00
private
2016-10-08 13:25:38 +02:00
2017-07-29 16:27:54 +02:00
def cask(header_token, **options, &block)
Cask.new(header_token, **options, &block)
end
2016-10-08 13:25:38 +02:00
end
class FromPathLoader < FromContentLoader
def self.can_load?(ref)
2017-06-28 09:25:14 +02:00
path = Pathname(ref)
path.extname == ".rb" && path.expand_path.exist?
end
attr_reader :token, :path
def initialize(path)
2017-06-28 09:25:14 +02:00
path = Pathname(path).expand_path
@token = path.basename(".rb").to_s
@path = path
end
def load
2017-06-28 09:25:14 +02:00
raise CaskUnavailableError.new(token, "'#{path}' does not exist.") unless path.exist?
raise CaskUnavailableError.new(token, "'#{path}' is not readable.") unless path.readable?
raise CaskUnavailableError.new(token, "'#{path}' is not a file.") unless path.file?
2017-06-28 09:25:14 +02:00
@content = IO.read(path)
instance_eval(content, path)
end
private
2017-07-29 16:27:54 +02:00
def cask(header_token, **options, &block)
2017-06-28 09:25:14 +02:00
if token != header_token
raise CaskTokenMismatchError.new(token, header_token)
end
2017-07-29 16:27:54 +02:00
super(header_token, **options, sourcefile_path: path, &block)
end
2016-10-08 13:25:38 +02:00
end
class FromURILoader < FromPathLoader
def self.can_load?(ref)
2017-10-08 15:20:58 +02:00
uri_regex = ::URI::DEFAULT_PARSER.make_regexp
ref.to_s.match?(Regexp.new('\A' + uri_regex.source + '\Z', uri_regex.options))
end
2017-06-11 02:00:59 +02:00
attr_reader :url
def initialize(url)
2017-06-11 02:00:59 +02:00
@url = URI(url)
super Hbc.cache/File.basename(@url.path)
end
def load
2017-06-28 09:25:14 +02:00
path.dirname.mkpath
begin
2017-06-28 09:25:14 +02:00
ohai "Downloading #{url}."
2017-08-08 18:10:13 +02:00
curl_download url, to: path
rescue ErrorDuringExecution
2017-06-28 09:25:14 +02:00
raise CaskUnavailableError.new(token, "Failed to download #{Formatter.url(url)}.")
end
super
end
2016-10-08 13:25:38 +02:00
end
2017-07-29 16:27:54 +02:00
class FromTapPathLoader < FromPathLoader
def self.can_load?(ref)
2018-03-29 21:49:30 +02:00
File.expand_path(ref).match?(HOMEBREW_TAP_PATH_REGEX) && super
end
2017-06-28 09:25:14 +02:00
attr_reader :tap
2017-07-29 16:27:54 +02:00
def initialize(tap_path)
2018-03-29 21:49:30 +02:00
@tap = Tap.from_path(File.expand_path(tap_path))
2017-07-29 16:27:54 +02:00
super tap_path
end
private
def cask(*args, &block)
super(*args, tap: tap, &block)
end
end
class FromTapLoader < FromTapPathLoader
def self.can_load?(ref)
ref.to_s.match?(HOMEBREW_TAP_CASK_REGEX)
end
def initialize(tapped_name)
2017-06-28 09:25:14 +02:00
user, repo, token = tapped_name.split("/", 3)
2017-07-29 16:27:54 +02:00
super Tap.fetch(user, repo).cask_dir/"#{token}.rb"
end
2016-10-08 13:25:38 +02:00
def load
2017-06-28 09:25:14 +02:00
tap.install unless tap.installed?
super
end
end
class FromInstanceLoader
attr_reader :cask
def self.can_load?(ref)
ref.is_a?(Cask)
end
def initialize(cask)
@cask = cask
end
def load
cask
end
end
class NullLoader < FromPathLoader
def self.can_load?(*)
true
end
def initialize(ref)
2017-06-28 09:25:14 +02:00
token = File.basename(ref, ".rb")
super CaskLoader.default_path(token)
end
def load
2017-06-28 09:25:14 +02:00
raise CaskUnavailableError.new(token, "No Cask with this name exists.")
end
end
def self.path(ref)
self.for(ref).path
end
def self.load(ref)
self.for(ref).load
end
def self.for(ref)
[
FromInstanceLoader,
2017-10-08 15:20:58 +02:00
FromContentLoader,
FromURILoader,
FromTapLoader,
2017-07-29 16:27:54 +02:00
FromTapPathLoader,
FromPathLoader,
].each do |loader_class|
return loader_class.new(ref) if loader_class.can_load?(ref)
end
2017-07-29 16:27:54 +02:00
if FromTapPathLoader.can_load?(default_path(ref))
return FromTapPathLoader.new(default_path(ref))
end
2016-10-08 13:25:38 +02:00
2017-07-29 16:27:54 +02:00
case (possible_tap_casks = tap_paths(ref)).count
when 1
return FromTapPathLoader.new(possible_tap_casks.first)
when 2..Float::INFINITY
loaders = possible_tap_casks.map(&FromTapPathLoader.method(:new))
2017-10-15 02:28:32 +02:00
raise CaskError, <<~EOS
2017-07-29 16:27:54 +02:00
Cask #{ref} exists in multiple taps:
#{loaders.map { |loader| " #{loader.tap}/#{loader.token}" }.join("\n")}
EOS
2016-10-08 13:25:38 +02:00
end
possible_installed_cask = Cask.new(ref)
if possible_installed_cask.installed?
return FromPathLoader.new(possible_installed_cask.installed_caskfile)
end
NullLoader.new(ref)
end
def self.default_path(token)
Hbc.default_tap.cask_dir/"#{token.to_s.downcase}.rb"
end
def self.tap_paths(token)
Tap.map { |t| t.cask_dir/"#{token.to_s.downcase}.rb" }
.select(&:exist?)
2016-10-08 13:25:38 +02:00
end
end
end