mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Use a Formulary
-like approach to load Casks.
This commit is contained in:
parent
c4d8b1696c
commit
d1995dad4b
@ -7,7 +7,6 @@ require "hbc/auditor"
|
||||
require "hbc/cache"
|
||||
require "hbc/cask"
|
||||
require "hbc/cask_loader"
|
||||
require "hbc/without_source"
|
||||
require "hbc/caskroom"
|
||||
require "hbc/checkable"
|
||||
require "hbc/cli"
|
||||
@ -24,7 +23,6 @@ require "hbc/macos"
|
||||
require "hbc/pkg"
|
||||
require "hbc/qualified_token"
|
||||
require "hbc/scopes"
|
||||
require "hbc/source"
|
||||
require "hbc/staged"
|
||||
require "hbc/system_command"
|
||||
require "hbc/topological_hash"
|
||||
@ -45,10 +43,7 @@ module Hbc
|
||||
Caskroom.ensure_caskroom_exists
|
||||
end
|
||||
|
||||
def self.load(query)
|
||||
odebug "Loading Cask definitions"
|
||||
cask = Source.for_query(query).load
|
||||
cask.dumpcask
|
||||
cask
|
||||
def self.load(ref)
|
||||
CaskLoader.load(ref)
|
||||
end
|
||||
end
|
||||
|
@ -1,44 +1,167 @@
|
||||
module Hbc
|
||||
class CaskLoader
|
||||
def self.load_from_file(path)
|
||||
raise CaskError, "File '#{path}' does not exist" unless path.exist?
|
||||
raise CaskError, "File '#{path}' is not readable" unless path.readable?
|
||||
raise CaskError, "File '#{path}' is not a plain file" unless path.file?
|
||||
|
||||
token = path.basename(".rb").to_s
|
||||
content = IO.read(path).force_encoding("UTF-8")
|
||||
|
||||
new(token, content, path).load
|
||||
end
|
||||
|
||||
def self.load_from_string(token, content)
|
||||
new(token, content).load
|
||||
module CaskLoader
|
||||
class FromContentLoader
|
||||
def initialize(content)
|
||||
@content = content
|
||||
end
|
||||
|
||||
def load
|
||||
instance_eval(@content, __FILE__, __LINE__)
|
||||
rescue CaskError, StandardError, ScriptError => e
|
||||
e.message.concat(" while loading '#{@token}'")
|
||||
e.message.concat(" from '#{@path}'") unless @path.nil?
|
||||
raise e, e.message
|
||||
instance_eval(@content.force_encoding("UTF-8"), __FILE__, __LINE__)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def initialize(token, content, path = nil)
|
||||
@token = token
|
||||
@content = content
|
||||
@path = path unless path.nil?
|
||||
def cask(header_token, &block)
|
||||
Cask.new(header_token, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class FromPathLoader < FromContentLoader
|
||||
def self.can_load?(ref)
|
||||
path = Pathname.new(ref)
|
||||
path.extname == ".rb" && path.expand_path.exist?
|
||||
end
|
||||
|
||||
attr_reader :token, :path
|
||||
|
||||
def initialize(path)
|
||||
path = Pathname.new(path).expand_path
|
||||
|
||||
@token = path.basename(".rb").to_s
|
||||
@path = path
|
||||
end
|
||||
|
||||
def load
|
||||
raise CaskError, "'#{@path}' does not exist." unless @path.exist?
|
||||
raise CaskError, "'#{@path}' is not readable." unless @path.readable?
|
||||
raise CaskError, "'#{@path}' is not a file." unless @path.file?
|
||||
|
||||
@content = IO.read(@path)
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cask(header_token, &block)
|
||||
raise CaskTokenDoesNotMatchError.new(@token, header_token) unless @token == header_token
|
||||
if @token != header_token
|
||||
raise CaskTokenDoesNotMatchError.new(@token, header_token)
|
||||
end
|
||||
|
||||
if @path.nil?
|
||||
Cask.new(@token, &block)
|
||||
else
|
||||
Cask.new(@token, sourcefile_path: @path, &block)
|
||||
end
|
||||
Cask.new(header_token, sourcefile_path: @path, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class FromURILoader < FromPathLoader
|
||||
def self.can_load?(ref)
|
||||
!(ref.to_s !~ ::URI.regexp)
|
||||
end
|
||||
|
||||
def initialize(url)
|
||||
@url = url
|
||||
uri = URI(url)
|
||||
super Hbc.cache/File.basename(uri.path)
|
||||
end
|
||||
|
||||
def load
|
||||
Hbc.cache.mkpath
|
||||
FileUtils.rm_f @path
|
||||
|
||||
begin
|
||||
ohai "Downloading #{@url}."
|
||||
curl @url, "-o", @path
|
||||
rescue ErrorDuringExecution
|
||||
raise CaskUnavailableError, @url
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
class FromTapLoader < FromPathLoader
|
||||
def self.can_load?(ref)
|
||||
!(ref.to_s !~ HOMEBREW_TAP_CASK_REGEX)
|
||||
end
|
||||
|
||||
def initialize(tapped_name)
|
||||
user, repo, token = tapped_name.split("/", 3).map(&:downcase)
|
||||
@tap = Tap.fetch(user, repo)
|
||||
|
||||
super @tap.cask_dir/"#{token}.rb"
|
||||
end
|
||||
|
||||
def load
|
||||
@tap.install unless @tap.installed?
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
class NullLoader < FromPathLoader
|
||||
def self.can_load?(*)
|
||||
true
|
||||
end
|
||||
|
||||
def initialize(ref)
|
||||
@token = File.basename(ref, ".rb")
|
||||
super CaskLoader.default_path(@token)
|
||||
end
|
||||
|
||||
def load
|
||||
raise CaskUnavailableError, @token
|
||||
end
|
||||
end
|
||||
|
||||
def self.load_from_file(path)
|
||||
FromPathLoader.new(path).load
|
||||
end
|
||||
|
||||
def self.load_from_string(content)
|
||||
FromContentLoader.new(content).load
|
||||
end
|
||||
|
||||
def self.path(ref)
|
||||
self.for(ref).path
|
||||
end
|
||||
|
||||
def self.load(ref)
|
||||
self.for(ref).load
|
||||
end
|
||||
|
||||
def self.for(ref)
|
||||
[
|
||||
FromURILoader,
|
||||
FromTapLoader,
|
||||
FromPathLoader,
|
||||
].each do |loader_class|
|
||||
return loader_class.new(ref) if loader_class.can_load?(ref)
|
||||
end
|
||||
|
||||
if FromPathLoader.can_load?(default_path(ref))
|
||||
return FromPathLoader.new(default_path(ref))
|
||||
end
|
||||
|
||||
possible_tap_casks = tap_paths(ref)
|
||||
if possible_tap_casks.count == 1
|
||||
possible_tap_cask = possible_tap_casks.first
|
||||
return FromPathLoader.new(possible_tap_cask)
|
||||
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?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -126,15 +126,14 @@ module Hbc
|
||||
end
|
||||
|
||||
if token_with_tap
|
||||
user, repo, token = token_with_tap.split("/")
|
||||
user, repo, token = token_with_tap.split("/", 3)
|
||||
tap = Tap.fetch(user, repo)
|
||||
else
|
||||
token = query_without_extension
|
||||
tap = Hbc.default_tap
|
||||
end
|
||||
|
||||
return query_path if tap.cask_dir.nil?
|
||||
tap.cask_dir.join("#{token}.rb")
|
||||
CaskLoader.default_path(token)
|
||||
end
|
||||
|
||||
def tcc_db
|
||||
|
@ -11,15 +11,15 @@ module Hbc
|
||||
end
|
||||
|
||||
def all_tapped_cask_dirs
|
||||
Tap.map(&:cask_dir).compact
|
||||
Tap.map(&:cask_dir).select(&:directory?)
|
||||
end
|
||||
|
||||
def all_tokens
|
||||
Tap.map do |t|
|
||||
Tap.flat_map do |t|
|
||||
t.cask_files.map do |p|
|
||||
"#{t.name}/#{File.basename(p, ".rb")}"
|
||||
end
|
||||
end.flatten
|
||||
end
|
||||
end
|
||||
|
||||
def installed
|
||||
|
@ -1,37 +0,0 @@
|
||||
require "hbc/source/gone"
|
||||
require "hbc/source/path_slash_required"
|
||||
require "hbc/source/path_slash_optional"
|
||||
require "hbc/source/tapped_qualified"
|
||||
require "hbc/source/untapped_qualified"
|
||||
require "hbc/source/tapped"
|
||||
require "hbc/source/uri"
|
||||
|
||||
module Hbc
|
||||
module Source
|
||||
def self.sources
|
||||
[
|
||||
URI,
|
||||
PathSlashRequired,
|
||||
TappedQualified,
|
||||
UntappedQualified,
|
||||
Tapped,
|
||||
PathSlashOptional,
|
||||
Gone,
|
||||
]
|
||||
end
|
||||
|
||||
def self.for_query(query)
|
||||
odebug "Translating '#{query}' into a valid Cask source"
|
||||
raise CaskUnavailableError, query if query.to_s =~ /^\s*$/
|
||||
source = sources.find do |s|
|
||||
odebug "Testing source class #{s}"
|
||||
s.me?(query)
|
||||
end
|
||||
raise CaskUnavailableError, query unless source
|
||||
odebug "Success! Using source class #{source}"
|
||||
resolved_cask_source = source.new(query)
|
||||
odebug "Resolved Cask URI or file source to '#{resolved_cask_source}'"
|
||||
resolved_cask_source
|
||||
end
|
||||
end
|
||||
end
|
@ -1,23 +0,0 @@
|
||||
module Hbc
|
||||
module Source
|
||||
class Gone
|
||||
def self.me?(query)
|
||||
WithoutSource.new(query).installed?
|
||||
end
|
||||
|
||||
attr_reader :query
|
||||
|
||||
def initialize(query)
|
||||
@query = query
|
||||
end
|
||||
|
||||
def load
|
||||
WithoutSource.new(query)
|
||||
end
|
||||
|
||||
def to_s
|
||||
""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,29 +0,0 @@
|
||||
require "rubygems"
|
||||
require "hbc/cask_loader"
|
||||
|
||||
module Hbc
|
||||
module Source
|
||||
class PathBase
|
||||
# derived classes must define method self.me?
|
||||
|
||||
def self.path_for_query(query)
|
||||
Pathname.new(query).sub(/(\.rb)?$/, ".rb")
|
||||
end
|
||||
|
||||
attr_reader :path
|
||||
|
||||
def initialize(path)
|
||||
@path = Pathname.new(path).expand_path
|
||||
end
|
||||
|
||||
def load
|
||||
CaskLoader.load_from_file(@path)
|
||||
end
|
||||
|
||||
def to_s
|
||||
# stringify to fully-resolved location
|
||||
@path.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,12 +0,0 @@
|
||||
require "hbc/source/path_base"
|
||||
|
||||
module Hbc
|
||||
module Source
|
||||
class PathSlashOptional < PathBase
|
||||
def self.me?(query)
|
||||
path = path_for_query(query)
|
||||
path.exist?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,12 +0,0 @@
|
||||
require "hbc/source/path_base"
|
||||
|
||||
module Hbc
|
||||
module Source
|
||||
class PathSlashRequired < PathBase
|
||||
def self.me?(query)
|
||||
path = path_for_query(query)
|
||||
path.to_s.include?("/") && path.exist?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,24 +0,0 @@
|
||||
module Hbc
|
||||
module Source
|
||||
class Tapped
|
||||
def self.me?(query)
|
||||
Hbc.path(query).exist?
|
||||
end
|
||||
|
||||
attr_reader :token
|
||||
|
||||
def initialize(token)
|
||||
@token = token
|
||||
end
|
||||
|
||||
def load
|
||||
PathSlashOptional.new(Hbc.path(token)).load
|
||||
end
|
||||
|
||||
def to_s
|
||||
# stringify to fully-resolved location
|
||||
Hbc.path(token).expand_path.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,21 +0,0 @@
|
||||
require "hbc/source/tapped"
|
||||
|
||||
module Hbc
|
||||
module Source
|
||||
class TappedQualified < Tapped
|
||||
def self.me?(query)
|
||||
return if (tap = tap_for_query(query)).nil?
|
||||
|
||||
tap.installed? && Hbc.path(query).exist?
|
||||
end
|
||||
|
||||
def self.tap_for_query(query)
|
||||
qualified_token = QualifiedToken.parse(query)
|
||||
return if qualified_token.nil?
|
||||
|
||||
user, repo = qualified_token[0..1]
|
||||
Tap.fetch(user, repo)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,14 +0,0 @@
|
||||
require "hbc/source/tapped_qualified"
|
||||
|
||||
module Hbc
|
||||
module Source
|
||||
class UntappedQualified < TappedQualified
|
||||
def self.me?(query)
|
||||
return if (tap = tap_for_query(query)).nil?
|
||||
|
||||
tap.install
|
||||
tap.installed? && Hbc.path(query).exist?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,32 +0,0 @@
|
||||
module Hbc
|
||||
module Source
|
||||
class URI
|
||||
def self.me?(query)
|
||||
!(query.to_s =~ ::URI.regexp).nil?
|
||||
end
|
||||
|
||||
attr_reader :uri
|
||||
|
||||
def initialize(uri)
|
||||
@uri = uri
|
||||
end
|
||||
|
||||
def load
|
||||
Hbc.cache.mkpath
|
||||
path = Hbc.cache.join(File.basename(uri))
|
||||
ohai "Downloading #{uri}"
|
||||
odebug "Download target -> #{path}"
|
||||
begin
|
||||
curl(uri, "-o", path.to_s)
|
||||
rescue ErrorDuringExecution
|
||||
raise CaskUnavailableError, uri
|
||||
end
|
||||
PathSlashOptional.new(path).load
|
||||
end
|
||||
|
||||
def to_s
|
||||
uri.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,17 +0,0 @@
|
||||
module Hbc
|
||||
class WithoutSource < Cask
|
||||
# Override from `Hbc::DSL` because we don't have a cask source file to work
|
||||
# with, so we don't know the cask's `version`.
|
||||
def staged_path
|
||||
(caskroom_path.children - [metadata_master_container_path]).first
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{token} (!)"
|
||||
end
|
||||
|
||||
def installed?
|
||||
caskroom_path.exist?
|
||||
end
|
||||
end
|
||||
end
|
@ -19,6 +19,11 @@ class String
|
||||
end
|
||||
end
|
||||
|
||||
def cask
|
||||
$LOAD_PATH.unshift("#{HOMEBREW_LIBRARY_PATH}/cask/lib")
|
||||
require "hbc"
|
||||
end
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
|
||||
|
@ -12,7 +12,11 @@ module CaskLoaderCompatibilityLayer
|
||||
end
|
||||
|
||||
module Hbc
|
||||
class CaskLoader
|
||||
module CaskLoader
|
||||
class FromContentLoader; end
|
||||
|
||||
class FromPathLoader < FromContentLoader
|
||||
prepend CaskLoaderCompatibilityLayer
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -285,7 +285,7 @@ class Tap
|
||||
|
||||
# path to the directory of all {Formula} files for this {Tap}.
|
||||
def formula_dir
|
||||
@formula_dir ||= potential_formula_dirs.detect(&:directory?)
|
||||
@formula_dir ||= potential_formula_dirs.detect(&:directory?) || path/"Formula"
|
||||
end
|
||||
|
||||
def potential_formula_dirs
|
||||
@ -294,12 +294,12 @@ class Tap
|
||||
|
||||
# path to the directory of all {Cask} files for this {Tap}.
|
||||
def cask_dir
|
||||
@cask_dir ||= [path/"Casks"].detect(&:directory?)
|
||||
@cask_dir ||= path/"Casks"
|
||||
end
|
||||
|
||||
# an array of all {Formula} files of this {Tap}.
|
||||
def formula_files
|
||||
@formula_files ||= if formula_dir
|
||||
@formula_files ||= if formula_dir.directory?
|
||||
formula_dir.children.select(&method(:formula_file?))
|
||||
else
|
||||
[]
|
||||
@ -308,7 +308,7 @@ class Tap
|
||||
|
||||
# an array of all {Cask} files of this {Tap}.
|
||||
def cask_files
|
||||
@cask_files ||= if cask_dir
|
||||
@cask_files ||= if cask_dir.directory?
|
||||
cask_dir.children.select(&method(:cask_file?))
|
||||
else
|
||||
[]
|
||||
|
@ -40,23 +40,6 @@ describe Hbc::CLI::List, :cask do
|
||||
end
|
||||
end
|
||||
|
||||
describe "when Casks have been renamed" do
|
||||
let(:caskroom_path) { Hbc.caskroom.join("ive-been-renamed") }
|
||||
let(:staged_path) { caskroom_path.join("latest") }
|
||||
|
||||
before do
|
||||
staged_path.mkpath
|
||||
end
|
||||
|
||||
it "lists installed Casks without backing ruby files (due to renames or otherwise)" do
|
||||
expect {
|
||||
Hbc::CLI::List.run
|
||||
}.to output(<<-EOS.undent).to_stdout
|
||||
ive-been-renamed (!)
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
describe "given a set of installed Casks" do
|
||||
let(:caffeine) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-caffeine.rb") }
|
||||
let(:transmission) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-transmission.rb") }
|
||||
|
Loading…
x
Reference in New Issue
Block a user