Merge pull request #16399 from jawshooah/casks-as-instances
Load casks as instances of Hbc::Cask rather than subclasses
This commit is contained in:
commit
b390b68a97
|
@ -3,17 +3,17 @@ cask 'ax88179' do
|
|||
sha256 '50b9754649cb9f67a1a911ff07e49c3fc5ac931c49f28dc3235adb95d31e3323'
|
||||
|
||||
module Utils
|
||||
def self.basename
|
||||
"AX88179_178A_Macintosh_10.6_to_10.11_Driver_Installer_v#{Module.nesting.last.version}"
|
||||
def self.basename(version)
|
||||
"AX88179_178A_Macintosh_10.6_to_10.11_Driver_Installer_v#{version}"
|
||||
end
|
||||
end
|
||||
|
||||
url "http://www.asix.com.tw/FrootAttach/driver/#{Utils.basename}.zip"
|
||||
url "http://www.asix.com.tw/FrootAttach/driver/#{Utils.basename(version)}.zip"
|
||||
name 'AX88179'
|
||||
homepage 'http://www.asix.com.tw/products.php?op=pItemdetail&PItemID=131;71;112&PLine=71'
|
||||
license :gratis
|
||||
|
||||
container :nested => "#{Utils.basename}/AX88179_178A.dmg"
|
||||
container :nested => "#{Utils.basename(version)}/AX88179_178A.dmg"
|
||||
|
||||
pkg "AX88179_178A_v#{version[0..-10]}.pkg"
|
||||
|
||||
|
|
|
@ -3,17 +3,17 @@ cask 'ax88772' do
|
|||
sha256 'cc336a77ed35ab6b9972f76fb2a4c77650072c2844fd1632a1875b035a311c6f'
|
||||
|
||||
module Utils
|
||||
def self.basename
|
||||
"AX88772C_772B_772A_760_772_Macintosh_10.5_to_10.11_Driver_Installer_v#{Module.nesting.last.version}"
|
||||
def self.basename(version)
|
||||
"AX88772C_772B_772A_760_772_Macintosh_10.5_to_10.11_Driver_Installer_v#{version}"
|
||||
end
|
||||
end
|
||||
|
||||
url "http://www.asix.com.tw/FrootAttach/driver/#{Utils.basename}.zip"
|
||||
url "http://www.asix.com.tw/FrootAttach/driver/#{Utils.basename(version)}.zip"
|
||||
name 'AX88772'
|
||||
homepage 'http://www.asix.com.tw/products.php?op=pItemdetail&PItemID=86;71;101&PLine=71'
|
||||
license :unknown # TODO: change license and remove this comment; ':unknown' is a machine-generated placeholder
|
||||
|
||||
container :nested => "#{Utils.basename}/AX88772.dmg"
|
||||
container :nested => "#{Utils.basename(version)}/AX88772.dmg"
|
||||
|
||||
pkg "AX88772_v#{version.major_minor_patch}.pkg"
|
||||
|
||||
|
|
|
@ -3,17 +3,17 @@ cask 'mcs783x' do
|
|||
sha256 'd86bdf6107cec7d3990f6967a5be782f7945cb722f22789cb04051514ba87a10'
|
||||
|
||||
module Utils
|
||||
def self.basename
|
||||
"MCS783x_Mac_OSX_10.5_to_10.10_driver_v#{Module.nesting.last.version}"
|
||||
def self.basename(version)
|
||||
"MCS783x_Mac_OSX_10.5_to_10.10_driver_v#{version}"
|
||||
end
|
||||
end
|
||||
|
||||
url "http://www.asix.com.tw/FrootAttach/driver/#{Utils.basename}.zip"
|
||||
url "http://www.asix.com.tw/FrootAttach/driver/#{Utils.basename(version)}.zip"
|
||||
name 'ASIX MCS7830/7832 USB to Ethernet Controller Driver'
|
||||
homepage 'http://www.asix.com.tw/products.php?op=pItemdetail&PItemID=108;71;101&PLine=71'
|
||||
license :unknown # TODO: change license and remove this comment; ':unknown' is a machine-generated placeholder
|
||||
|
||||
container :nested => "#{Utils.basename}/MCS7830_v#{version.major_minor_patch}.dmg"
|
||||
container :nested => "#{Utils.basename(version)}/MCS7830_v#{version.major_minor_patch}.dmg"
|
||||
|
||||
pkg "MCS7830 v#{version.major_minor_patch}.pkg"
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class Hbc::Audit
|
|||
add_error "a #{sym} stanza is required" unless cask.send(sym)
|
||||
end
|
||||
add_error 'a license stanza is required (:unknown is OK)' unless cask.license
|
||||
add_error 'at least one name stanza is required' if cask.full_name.empty?
|
||||
add_error 'at least one name stanza is required' if cask.name.empty?
|
||||
# todo: specific DSL knowledge should not be spread around in various files like this
|
||||
# todo: nested_container should not still be a pseudo-artifact at this point
|
||||
installable_artifacts = cask.artifacts.reject{ |k,v| [:uninstall, :zap, :nested_container].include?(k)}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
require 'forwardable'
|
||||
|
||||
require 'hbc/dsl'
|
||||
|
||||
class Hbc::Cask
|
||||
include Hbc::DSL
|
||||
|
||||
def self.token
|
||||
# todo removeme: prepending KlassPrefix is transitional as we move away from representing Casks as classes
|
||||
self.name.sub(/^KlassPrefix/,'').gsub(/([a-zA-Z\d])([A-Z])/,'\1-\2').gsub(/([a-zA-Z\d])([A-Z])/,'\1-\2').downcase
|
||||
end
|
||||
extend Forwardable
|
||||
|
||||
attr_reader :token, :sourcefile_path
|
||||
def initialize(sourcefile_path=nil)
|
||||
def initialize(token, sourcefile_path: nil, dsl: nil, &block)
|
||||
@token = token
|
||||
@sourcefile_path = sourcefile_path
|
||||
@token = self.class.token
|
||||
@dsl = dsl || Hbc::DSL.new(@token)
|
||||
@dsl.instance_eval(&block) if block_given?
|
||||
end
|
||||
|
||||
Hbc::DSL::DSL_METHODS.each do |method_name|
|
||||
define_method(method_name) { @dsl.send(method_name) }
|
||||
end
|
||||
|
||||
METADATA_SUBDIR = '.metadata'
|
||||
|
@ -74,7 +77,7 @@ class Hbc::Cask
|
|||
odebug "Cask instance dumps in YAML:"
|
||||
odebug "Cask instance toplevel:", self.to_yaml
|
||||
[
|
||||
:full_name,
|
||||
:name,
|
||||
:homepage,
|
||||
:url,
|
||||
:appcast,
|
||||
|
@ -90,9 +93,7 @@ class Hbc::Cask
|
|||
:accessibility_access,
|
||||
:auto_updates
|
||||
].each do |method|
|
||||
printable_method = method.to_s
|
||||
printable_method = "name" if printable_method == "full_name"
|
||||
odebug "Cask instance method '#{printable_method}':", self.send(method).to_yaml
|
||||
odebug "Cask instance method '#{method}':", self.send(method).to_yaml
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -115,14 +115,15 @@ class Hbc::CLI
|
|||
command = lookup_command(command_string)
|
||||
run_command(command, *rest)
|
||||
rescue Hbc::CaskError, Hbc::CaskSha256MismatchError => e
|
||||
onoe e
|
||||
$stderr.puts Hbc::Utils.error_message_with_suggestions if e.is_a?(Hbc::CaskHeaderParseError)
|
||||
$stderr.puts e.backtrace if Hbc.debug
|
||||
msg = e.message
|
||||
msg << e.backtrace.join("\n") if Hbc.debug
|
||||
onoe msg
|
||||
exit 1
|
||||
rescue StandardError, ScriptError, NoMemoryError => e
|
||||
onoe e
|
||||
$stderr.puts Hbc::Utils.error_message_with_suggestions
|
||||
$stderr.puts e.backtrace
|
||||
msg = e.message
|
||||
msg << Hbc::Utils.error_message_with_suggestions
|
||||
msg << e.backtrace.join("\n")
|
||||
onoe msg
|
||||
exit 1
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ class Hbc::CLI::Base
|
|||
end
|
||||
|
||||
def self.cask_tokens_from(args)
|
||||
args.reject { |a| a.chars.first == '-' }
|
||||
args.reject { |a| a.empty? || a.chars.first == '-' }
|
||||
end
|
||||
|
||||
def self.help
|
||||
|
|
|
@ -23,7 +23,7 @@ class Hbc::CLI::Info < Hbc::CLI::Base
|
|||
# todo completely reformat the info report
|
||||
<<-PURPOSE
|
||||
#{cask}: #{cask.version}
|
||||
#{formatted_full_name(cask) }
|
||||
#{formatted_name(cask) }
|
||||
#{cask.homepage or 'No Homepage'}
|
||||
#{installation}
|
||||
#{github_info(cask) or 'No GitHub URL'}
|
||||
|
@ -31,9 +31,9 @@ class Hbc::CLI::Info < Hbc::CLI::Base
|
|||
PURPOSE
|
||||
end
|
||||
|
||||
def self.formatted_full_name(cask)
|
||||
def self.formatted_name(cask)
|
||||
# todo transitional: make name a required stanza, and then stop substituting cask.token here
|
||||
cask.full_name.empty? ? cask.token : cask.full_name.join(', ')
|
||||
cask.name.empty? ? cask.token : cask.name.join(', ')
|
||||
end
|
||||
|
||||
def self.github_info(cask)
|
||||
|
@ -58,7 +58,7 @@ PURPOSE
|
|||
|
||||
def self.artifact_info(cask)
|
||||
retval = ''
|
||||
Hbc::DSL::ClassMethods.ordinary_artifact_types.each do |type|
|
||||
Hbc::DSL::ORDINARY_ARTIFACT_TYPES.each do |type|
|
||||
if cask.artifacts[type].length > 0
|
||||
retval = "#{Tty.blue.bold}==>#{Tty.reset.bold} Contents#{Tty.reset}\n" unless retval.length > 0
|
||||
cask.artifacts[type].each do |artifact|
|
||||
|
|
|
@ -71,7 +71,6 @@ class Hbc::CLI::InternalStanza < Hbc::CLI::InternalUseBase
|
|||
|
||||
def self.print_stanzas(stanza, format=nil, table=nil, quiet=nil, *cask_tokens)
|
||||
count = 0
|
||||
stanza = :full_name if stanza == :name
|
||||
if ARTIFACTS.include?(stanza)
|
||||
artifact_name = stanza
|
||||
stanza = :artifacts
|
||||
|
|
527
lib/hbc/dsl.rb
527
lib/hbc/dsl.rb
|
@ -1,6 +1,6 @@
|
|||
require 'set'
|
||||
|
||||
module Hbc::DSL; end
|
||||
class Hbc::DSL; end
|
||||
|
||||
require 'hbc/dsl/appcast'
|
||||
require 'hbc/dsl/base'
|
||||
|
@ -16,312 +16,283 @@ require 'hbc/dsl/uninstall_postflight'
|
|||
require 'hbc/dsl/uninstall_preflight'
|
||||
require 'hbc/dsl/version'
|
||||
|
||||
module Hbc::DSL
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
class Hbc::DSL
|
||||
ORDINARY_ARTIFACT_TYPES = [
|
||||
:app,
|
||||
:artifact,
|
||||
:audio_unit_plugin,
|
||||
:binary,
|
||||
:colorpicker,
|
||||
:font,
|
||||
:input_method,
|
||||
:internet_plugin,
|
||||
:pkg,
|
||||
:prefpane,
|
||||
:qlplugin,
|
||||
:screen_saver,
|
||||
:service,
|
||||
:stage_only,
|
||||
:suite,
|
||||
:vst_plugin
|
||||
]
|
||||
|
||||
ACTIVATABLE_ARTIFACT_TYPES = [:installer, *ORDINARY_ARTIFACT_TYPES] - [:stage_only]
|
||||
|
||||
SPECIAL_ARTIFACT_TYPES = [
|
||||
:uninstall,
|
||||
:zap,
|
||||
]
|
||||
|
||||
ARTIFACT_BLOCK_TYPES = [
|
||||
:preflight,
|
||||
:postflight,
|
||||
:uninstall_preflight,
|
||||
:uninstall_postflight,
|
||||
]
|
||||
|
||||
DSL_METHODS = Set.new [
|
||||
:accessibility_access,
|
||||
:appcast,
|
||||
:artifacts,
|
||||
:auto_updates,
|
||||
:caskroom_path,
|
||||
:caveats,
|
||||
:conflicts_with,
|
||||
:container,
|
||||
:depends_on,
|
||||
:gpg,
|
||||
:homepage,
|
||||
:license,
|
||||
:name,
|
||||
:sha256,
|
||||
:staged_path,
|
||||
:url,
|
||||
:version,
|
||||
*ORDINARY_ARTIFACT_TYPES,
|
||||
*ACTIVATABLE_ARTIFACT_TYPES,
|
||||
*SPECIAL_ARTIFACT_TYPES,
|
||||
*ARTIFACT_BLOCK_TYPES
|
||||
]
|
||||
|
||||
attr_reader :token
|
||||
def initialize(token)
|
||||
@token = token
|
||||
end
|
||||
|
||||
def full_name; self.class.full_name; end
|
||||
def name(*args)
|
||||
@name ||= []
|
||||
return @name if args.empty?
|
||||
@name.concat(args.flatten)
|
||||
end
|
||||
|
||||
def homepage; self.class.homepage; end
|
||||
def homepage(homepage=nil)
|
||||
if @homepage and !homepage.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'homepage' stanza may only appear once")
|
||||
end
|
||||
@homepage ||= homepage
|
||||
end
|
||||
|
||||
def url; self.class.url; end
|
||||
def url(*args)
|
||||
return @url if args.empty?
|
||||
if @url and !args.empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'url' stanza may only appear once")
|
||||
end
|
||||
@url ||= begin
|
||||
Hbc::URL.new(*args)
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'url' stanza failed with: #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
def appcast; self.class.appcast; end
|
||||
def appcast(*args)
|
||||
return @appcast if args.empty?
|
||||
if @appcast and !args.empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'appcast' stanza may only appear once")
|
||||
end
|
||||
@appcast ||= begin
|
||||
Hbc::DSL::Appcast.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
def gpg; self.class.gpg; end
|
||||
def gpg(*args)
|
||||
return @gpg if args.empty?
|
||||
if @gpg and !args.empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'gpg' stanza may only appear once")
|
||||
end
|
||||
@gpg ||= begin
|
||||
Hbc::DSL::Gpg.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
def version; self.class.version; end
|
||||
def container(*args)
|
||||
return @container if args.empty?
|
||||
if @container and !args.empty?
|
||||
# todo: remove this constraint, and instead merge multiple container stanzas
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'container' stanza may only appear once")
|
||||
end
|
||||
@container ||= begin
|
||||
Hbc::DSL::Container.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
# todo: remove this backward-compatibility section after removing nested_container
|
||||
if @container and @container.nested
|
||||
artifacts[:nested_container] << @container.nested
|
||||
end
|
||||
@container
|
||||
end
|
||||
|
||||
def license; self.class.license; end
|
||||
SYMBOLIC_VERSIONS = Set.new [
|
||||
:latest,
|
||||
]
|
||||
|
||||
def depends_on; self.class.depends_on; end
|
||||
def version(arg=nil)
|
||||
if arg.nil?
|
||||
return @version
|
||||
elsif @version
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'version' stanza may only appear once")
|
||||
elsif !arg.is_a?(String) and !SYMBOLIC_VERSIONS.include?(arg)
|
||||
raise Hbc::CaskInvalidError.new(self.token, "invalid 'version' value: '#{arg.inspect}'")
|
||||
end
|
||||
@version ||= Hbc::DSL::Version.new(arg)
|
||||
end
|
||||
|
||||
def conflicts_with; self.class.conflicts_with; end
|
||||
SYMBOLIC_SHA256S = Set.new [
|
||||
:no_check,
|
||||
]
|
||||
|
||||
def container; self.class.container; end
|
||||
def sha256(arg=nil)
|
||||
if arg.nil?
|
||||
return @sha256
|
||||
elsif @sha256
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'sha256' stanza may only appear once")
|
||||
elsif !arg.is_a?(String) and !SYMBOLIC_SHA256S.include?(arg)
|
||||
raise Hbc::CaskInvalidError.new(self.token, "invalid 'sha256' value: '#{arg.inspect}'")
|
||||
end
|
||||
@sha256 ||= arg
|
||||
end
|
||||
|
||||
def sha256; self.class.sha256; end
|
||||
def license(arg=nil)
|
||||
return @license if arg.nil?
|
||||
if @license and !arg.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'license' stanza may only appear once")
|
||||
end
|
||||
@license ||= begin
|
||||
Hbc::DSL::License.new(arg) unless arg.nil?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
def artifacts; self.class.artifacts; end
|
||||
# depends_on uses a load method so that multiple stanzas can be merged
|
||||
def depends_on(*args)
|
||||
return @depends_on if args.empty?
|
||||
@depends_on ||= Hbc::DSL::DependsOn.new()
|
||||
begin
|
||||
@depends_on.load(*args) unless args.empty?
|
||||
rescue RuntimeError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
@depends_on
|
||||
end
|
||||
|
||||
def caskroom_path; self.class.caskroom_path; end
|
||||
def conflicts_with(*args)
|
||||
if @conflicts_with and !args.empty?
|
||||
# todo: remove this constraint, and instead merge multiple conflicts_with stanzas
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'conflicts_with' stanza may only appear once")
|
||||
end
|
||||
return @conflicts_with if args.empty?
|
||||
@conflicts_with ||= begin
|
||||
Hbc::DSL::ConflictsWith.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
def staged_path; self.class.staged_path; end
|
||||
def artifacts
|
||||
@artifacts ||= Hash.new { |hash, key| hash[key] = Set.new }
|
||||
end
|
||||
|
||||
def caveats; self.class.caveats; end
|
||||
def caskroom_path
|
||||
@caskroom_path ||= Hbc.caskroom.join(self.token)
|
||||
end
|
||||
|
||||
def accessibility_access; self.class.accessibility_access; end
|
||||
def staged_path
|
||||
return @staged_path if @staged_path
|
||||
cask_version = self.version || :unknown
|
||||
@staged_path = self.caskroom_path.join(cask_version.to_s)
|
||||
end
|
||||
|
||||
def auto_updates; self.class.auto_updates; end
|
||||
def caveats(*string, &block)
|
||||
@caveats ||= []
|
||||
if block_given?
|
||||
@caveats << Hbc::Caveats.new(block)
|
||||
elsif string.any?
|
||||
@caveats << string.map{ |s| s.to_s.sub(/[\r\n \t]*\Z/, "\n\n") }
|
||||
else
|
||||
# accessor
|
||||
@caveats
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def accessibility_access(accessibility_access=nil)
|
||||
if @accessibility_access and !accessibility_access.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'accessibility_access' stanza may only appear once")
|
||||
end
|
||||
@accessibility_access ||= accessibility_access
|
||||
end
|
||||
|
||||
# A quite fragile shim to allow "full_name" be exposed as simply "name"
|
||||
# in the DSL. We detect the difference with the already-existing "name"
|
||||
# method by arity, and use "full_name" exclusively in backend code.
|
||||
def name(*args)
|
||||
if args.empty?
|
||||
super
|
||||
else
|
||||
self.full_name(args)
|
||||
def auto_updates(auto_updates=nil)
|
||||
if @auto_updates and !auto_updates.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'auto_updates' stanza may only appear once")
|
||||
end
|
||||
@auto_updates ||= auto_updates
|
||||
end
|
||||
|
||||
ORDINARY_ARTIFACT_TYPES.each do |type|
|
||||
define_method(type) do |*args|
|
||||
if type == :stage_only and args != [true]
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'stage_only' takes a single argument: true")
|
||||
end
|
||||
artifacts[type] << args
|
||||
if artifacts.key?(:stage_only) and
|
||||
artifacts.keys.count > 1 and
|
||||
! (artifacts.keys & ACTIVATABLE_ARTIFACT_TYPES).empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'stage_only' must be the only activatable artifact")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def full_name(_full_name=nil)
|
||||
@full_name ||= []
|
||||
if _full_name
|
||||
@full_name.concat(Array(*_full_name))
|
||||
end
|
||||
@full_name
|
||||
def installer(*args)
|
||||
if args.empty?
|
||||
return artifacts[:installer]
|
||||
end
|
||||
|
||||
def homepage(homepage=nil)
|
||||
if @homepage and !homepage.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'homepage' stanza may only appear once")
|
||||
end
|
||||
@homepage ||= homepage
|
||||
begin
|
||||
artifacts[:installer] << Hbc::DSL::Installer.new(*args)
|
||||
raise "'stage_only' must be the only activatable artifact" if artifacts.key?(:stage_only)
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
def url(*args)
|
||||
return @url if args.empty?
|
||||
if @url and !args.empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'url' stanza may only appear once")
|
||||
end
|
||||
@url ||= begin
|
||||
Hbc::URL.new(*args)
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'url' stanza failed with: #{e}")
|
||||
end
|
||||
SPECIAL_ARTIFACT_TYPES.each do |type|
|
||||
define_method(type) do |*args|
|
||||
artifacts[type].merge(args)
|
||||
end
|
||||
end
|
||||
|
||||
def appcast(*args)
|
||||
return @appcast if args.empty?
|
||||
if @appcast and !args.empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'appcast' stanza may only appear once")
|
||||
end
|
||||
@appcast ||= begin
|
||||
Hbc::DSL::Appcast.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
ARTIFACT_BLOCK_TYPES.each do |type|
|
||||
define_method(type) do |&block|
|
||||
artifacts[type] << block
|
||||
end
|
||||
end
|
||||
|
||||
def gpg(*args)
|
||||
return @gpg if args.empty?
|
||||
if @gpg and !args.empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'gpg' stanza may only appear once")
|
||||
end
|
||||
@gpg ||= begin
|
||||
Hbc::DSL::Gpg.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
def container(*args)
|
||||
return @container if args.empty?
|
||||
if @container and !args.empty?
|
||||
# todo: remove this constraint, and instead merge multiple container stanzas
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'container' stanza may only appear once")
|
||||
end
|
||||
@container ||= begin
|
||||
Hbc::DSL::Container.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
# todo: remove this backward-compatibility section after removing nested_container
|
||||
if @container and @container.nested
|
||||
artifacts[:nested_container] << @container.nested
|
||||
end
|
||||
@container
|
||||
end
|
||||
|
||||
SYMBOLIC_VERSIONS = Set.new [
|
||||
:latest,
|
||||
]
|
||||
|
||||
def version(arg=nil)
|
||||
if arg.nil?
|
||||
return @version
|
||||
elsif @version
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'version' stanza may only appear once")
|
||||
elsif !arg.is_a?(String) and !SYMBOLIC_VERSIONS.include?(arg)
|
||||
raise Hbc::CaskInvalidError.new(self.token, "invalid 'version' value: '#{arg.inspect}'")
|
||||
end
|
||||
@version ||= Hbc::DSL::Version.new(arg)
|
||||
end
|
||||
|
||||
SYMBOLIC_SHA256S = Set.new [
|
||||
:no_check,
|
||||
]
|
||||
|
||||
def sha256(arg=nil)
|
||||
if arg.nil?
|
||||
return @sha256
|
||||
elsif @sha256
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'sha256' stanza may only appear once")
|
||||
elsif !arg.is_a?(String) and !SYMBOLIC_SHA256S.include?(arg)
|
||||
raise Hbc::CaskInvalidError.new(self.token, "invalid 'sha256' value: '#{arg.inspect}'")
|
||||
end
|
||||
@sha256 ||= arg
|
||||
end
|
||||
|
||||
def license(arg=nil)
|
||||
return @license if arg.nil?
|
||||
if @license and !arg.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'license' stanza may only appear once")
|
||||
end
|
||||
@license ||= begin
|
||||
Hbc::DSL::License.new(arg) unless arg.nil?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
# depends_on uses a load method so that multiple stanzas can be merged
|
||||
def depends_on(*args)
|
||||
return @depends_on if args.empty?
|
||||
@depends_on ||= Hbc::DSL::DependsOn.new()
|
||||
begin
|
||||
@depends_on.load(*args) unless args.empty?
|
||||
rescue RuntimeError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
@depends_on
|
||||
end
|
||||
|
||||
def conflicts_with(*args)
|
||||
if @conflicts_with and !args.empty?
|
||||
# todo: remove this constraint, and instead merge multiple conflicts_with stanzas
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'conflicts_with' stanza may only appear once")
|
||||
end
|
||||
return @conflicts_with if args.empty?
|
||||
@conflicts_with ||= begin
|
||||
Hbc::DSL::ConflictsWith.new(*args) unless args.empty?
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
def artifacts
|
||||
@artifacts ||= Hash.new { |hash, key| hash[key] = Set.new }
|
||||
end
|
||||
|
||||
def caskroom_path
|
||||
@caskroom_path ||= Hbc.caskroom.join(self.token)
|
||||
end
|
||||
|
||||
def staged_path
|
||||
return @staged_path if @staged_path
|
||||
cask_version = self.version || :unknown
|
||||
@staged_path = self.caskroom_path.join(cask_version.to_s)
|
||||
end
|
||||
|
||||
def caveats(*string, &block)
|
||||
@caveats ||= []
|
||||
if block_given?
|
||||
@caveats << Hbc::Caveats.new(block)
|
||||
elsif string.any?
|
||||
@caveats << string.map{ |s| s.to_s.sub(/[\r\n \t]*\Z/, "\n\n") }
|
||||
else
|
||||
# accessor
|
||||
@caveats
|
||||
end
|
||||
end
|
||||
|
||||
def accessibility_access(accessibility_access=nil)
|
||||
if @accessibility_access and !accessibility_access.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'accessibility_access' stanza may only appear once")
|
||||
end
|
||||
@accessibility_access ||= accessibility_access
|
||||
end
|
||||
|
||||
def auto_updates(auto_updates=nil)
|
||||
if @auto_updates and !auto_updates.nil?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'auto_updates' stanza may only appear once")
|
||||
end
|
||||
@auto_updates ||= auto_updates
|
||||
end
|
||||
|
||||
def self.ordinary_artifact_types
|
||||
@@ordinary_artifact_types ||= [
|
||||
:app,
|
||||
:suite,
|
||||
:artifact,
|
||||
:prefpane,
|
||||
:qlplugin,
|
||||
:font,
|
||||
:service,
|
||||
:colorpicker,
|
||||
:binary,
|
||||
:input_method,
|
||||
:internet_plugin,
|
||||
:audio_unit_plugin,
|
||||
:vst_plugin,
|
||||
:screen_saver,
|
||||
:pkg,
|
||||
:stage_only,
|
||||
]
|
||||
end
|
||||
|
||||
def self.activatable_artifact_types
|
||||
@@activatable_artifact_types ||= [:installer, *ordinary_artifact_types] - [:stage_only]
|
||||
end
|
||||
|
||||
ordinary_artifact_types.each do |type|
|
||||
define_method(type) do |*args|
|
||||
if type == :stage_only and args != [true]
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'stage_only' takes a single argument: true")
|
||||
end
|
||||
artifacts[type] << args
|
||||
if artifacts.key?(:stage_only) and
|
||||
artifacts.keys.count > 1 and
|
||||
! (artifacts.keys & Hbc::DSL::ClassMethods.activatable_artifact_types).empty?
|
||||
raise Hbc::CaskInvalidError.new(self.token, "'stage_only' must be the only activatable artifact")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def installer(*args)
|
||||
if args.empty?
|
||||
return artifacts[:installer]
|
||||
end
|
||||
begin
|
||||
artifacts[:installer] << Hbc::DSL::Installer.new(*args)
|
||||
raise "'stage_only' must be the only activatable artifact" if artifacts.key?(:stage_only)
|
||||
rescue StandardError => e
|
||||
raise Hbc::CaskInvalidError.new(self.token, e)
|
||||
end
|
||||
end
|
||||
|
||||
SPECIAL_ARTIFACT_TYPES = [
|
||||
:uninstall,
|
||||
:zap,
|
||||
]
|
||||
|
||||
SPECIAL_ARTIFACT_TYPES.each do |type|
|
||||
define_method(type) do |*args|
|
||||
artifacts[type].merge(args)
|
||||
end
|
||||
end
|
||||
|
||||
ARTIFACT_BLOCK_TYPES = [
|
||||
:preflight,
|
||||
:postflight,
|
||||
:uninstall_preflight,
|
||||
:uninstall_postflight,
|
||||
]
|
||||
|
||||
ARTIFACT_BLOCK_TYPES.each do |type|
|
||||
define_method(type) do |&block|
|
||||
artifacts[type] << block
|
||||
end
|
||||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
Hbc::Utils.method_missing_message(method, self.token)
|
||||
return nil
|
||||
end
|
||||
def method_missing(method, *args)
|
||||
Hbc::Utils.method_missing_message(method, self.token)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -126,7 +126,10 @@ class Hbc::CaskInvalidError < Hbc::CaskError
|
|||
end
|
||||
end
|
||||
|
||||
class Hbc::CaskHeaderParseError < Hbc::CaskInvalidError
|
||||
class Hbc::CaskTokenDoesNotMatchError < Hbc::CaskInvalidError
|
||||
def initialize(token, header_token)
|
||||
super(token, "Bad header line: '#{header_token}' does not match file name")
|
||||
end
|
||||
end
|
||||
|
||||
class Hbc::CaskSha256MissingError < ArgumentError
|
||||
|
|
|
@ -5,7 +5,8 @@ module Hbc::Scopes
|
|||
|
||||
module ClassMethods
|
||||
def all
|
||||
all_tokens.map { |c| self.load c }
|
||||
@all_casks ||= {}
|
||||
all_tokens.map { |t| @all_casks[t] ||= self.load(t) }
|
||||
end
|
||||
|
||||
def all_tapped_cask_dirs
|
||||
|
@ -35,12 +36,13 @@ module Hbc::Scopes
|
|||
c = c.split('/').last 4
|
||||
# => ["caskroom", "example-tap", "Casks", "example"]
|
||||
c.delete_at(-2)
|
||||
# => ["example-tap", "example"]
|
||||
# => ["caskroom", "example-tap", "example"]
|
||||
c = c.join '/'
|
||||
}
|
||||
end
|
||||
|
||||
def installed
|
||||
@installed ||= {}
|
||||
installed_cask_dirs = Pathname.glob(caskroom.join("*"))
|
||||
# Hbc.load has some DWIM which is slow. Optimize here
|
||||
# by spoon-feeding Hbc.load fully-qualified paths.
|
||||
|
@ -52,9 +54,9 @@ module Hbc::Scopes
|
|||
tap_dir.join("#{cask_token}.rb").exist?
|
||||
end
|
||||
if path_to_cask
|
||||
Hbc.load(path_to_cask.join("#{cask_token}.rb"))
|
||||
@installed[cask_token] ||= Hbc.load(path_to_cask.join("#{cask_token}.rb"))
|
||||
else
|
||||
Hbc.load(cask_token)
|
||||
@installed[cask_token] ||= Hbc.load(cask_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,76 +20,48 @@ class Hbc::Source::PathBase
|
|||
raise Hbc::CaskError.new "File '#{path}' does not exist" unless path.exist?
|
||||
raise Hbc::CaskError.new "File '#{path}' is not readable" unless path.readable?
|
||||
raise Hbc::CaskError.new "File '#{path}' is not a plain file" unless path.file?
|
||||
begin
|
||||
|
||||
# transitional hack: convert first lines of the new form
|
||||
#
|
||||
# cask 'google-chrome' do
|
||||
#
|
||||
# to the old form
|
||||
#
|
||||
# class GoogleChrome < Hbc (class GoogleChrome < Cask)
|
||||
#
|
||||
# limitation: does not support Ruby extended quoting such as %Q{}
|
||||
#
|
||||
# todo: in the future, this can be pared down to an "eval"
|
||||
|
||||
# read Cask
|
||||
cask_contents = File.open(path, 'rb') do |handle|
|
||||
contents = handle.read
|
||||
if defined?(Encoding)
|
||||
contents.force_encoding('UTF-8')
|
||||
else
|
||||
contents
|
||||
end
|
||||
end
|
||||
|
||||
# munge text
|
||||
cask_contents.sub!(%r{\A(\s*\#[^\n]*\n)+}, '');
|
||||
if %r{\A\s*(test_)?cask\s+(?::v[\d_]+(test)?\s+=>\s+)?([\'\"])(\S+?)\3(?:\s*,\s*|\s+)do\s*\n}.match(cask_contents)
|
||||
is_test = $1 || $2
|
||||
header_token = $4
|
||||
superclass_name = is_test ? 'Hbc::TestCask' : 'Hbc::Cask'
|
||||
cask_contents.sub!(%r{\A[^\n]+\n}, "class #{cask_class_name} < #{superclass_name}\n")
|
||||
if header_token != cask_token
|
||||
raise Hbc::CaskInvalidError.new(cask_token, "Bad header line: '#{header_token}' does not match file name")
|
||||
end
|
||||
else
|
||||
raise Hbc::CaskHeaderParseError.new(cask_token, "Bad header line: parse failed")
|
||||
end
|
||||
|
||||
# simulate "require"
|
||||
begin
|
||||
Object.const_get(cask_class_name)
|
||||
rescue NameError
|
||||
eval(cask_contents, TOPLEVEL_BINDING)
|
||||
end
|
||||
|
||||
rescue Hbc::CaskError, StandardError, ScriptError => e
|
||||
# bug: e.message.concat doesn't work with Hbc::CaskError exceptions
|
||||
e.message.concat(" while loading '#{path}'")
|
||||
raise e
|
||||
end
|
||||
begin
|
||||
Object.const_get(cask_class_name).new(path)
|
||||
rescue Hbc::CaskError, StandardError, ScriptError => e
|
||||
# bug: e.message.concat doesn't work with Hbc::CaskError exceptions
|
||||
e.message.concat(" while instantiating '#{cask_class_name}' from '#{path}'")
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
def cask_token
|
||||
path.basename.to_s.sub(/\.rb/, '')
|
||||
end
|
||||
|
||||
def cask_class_name
|
||||
# todo removeme: prepending KlassPrefix is transitional as we move away from representing Casks as classes
|
||||
'KlassPrefix'.concat cask_token.split('-').map(&:capitalize).join
|
||||
load_cask
|
||||
end
|
||||
|
||||
def to_s
|
||||
# stringify to fully-resolved location
|
||||
path.to_s
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_cask
|
||||
instance_eval(cask_contents, __FILE__, __LINE__)
|
||||
rescue Hbc::CaskError, StandardError, ScriptError => e
|
||||
# bug: e.message.concat doesn't work with Hbc::CaskError exceptions
|
||||
raise e, e.message.concat(" while loading '#{path}'")
|
||||
end
|
||||
|
||||
def cask_contents
|
||||
File.open(path, 'rb') do |handle|
|
||||
contents = handle.read
|
||||
if defined?(Encoding)
|
||||
contents.force_encoding('UTF-8')
|
||||
else
|
||||
contents
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cask(header_token, &block)
|
||||
build_cask(Hbc::Cask, header_token, &block)
|
||||
end
|
||||
|
||||
def test_cask(header_token, &block)
|
||||
build_cask(Hbc::TestCask, header_token, &block)
|
||||
end
|
||||
|
||||
def build_cask(cask_class, header_token, &block)
|
||||
raise Hbc::CaskTokenDoesNotMatchError.new(cask_token, header_token) unless cask_token == header_token
|
||||
cask_class.new(cask_token, sourcefile_path: path, &block)
|
||||
end
|
||||
|
||||
def cask_token
|
||||
path.basename.to_s.sub(/\.rb/, '')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +1,4 @@
|
|||
class Hbc::WithoutSource < Hbc::Cask
|
||||
def initialize(sourcefile_path=nil)
|
||||
@sourcefile_path = sourcefile_path
|
||||
@token = sourcefile_path
|
||||
end
|
||||
|
||||
# Override from `Hbc::DSL` because `@token` is set to the constructor argument
|
||||
# instead of `self.class.token` as in `Hbc::Cask`.
|
||||
def caskroom_path
|
||||
Hbc.caskroom.join(token)
|
||||
end
|
||||
|
||||
# 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
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'spec_helper'
|
|||
describe Hbc::Audit do
|
||||
include AuditMatchers
|
||||
|
||||
let(:cask) { Hbc::Cask.new }
|
||||
let(:cask) { instance_double(Hbc::Cask) }
|
||||
let(:download) { false }
|
||||
let(:audit) { Hbc::Audit.new(cask, download) }
|
||||
|
||||
|
@ -125,7 +125,8 @@ describe Hbc::Audit do
|
|||
end
|
||||
|
||||
describe "audit of downloads" do
|
||||
let(:cask) { Hbc::Cask.new }
|
||||
let(:cask_token) { 'with-binary' }
|
||||
let(:cask) { Hbc.load(cask_token) }
|
||||
let(:download) { instance_double(Hbc::Download) }
|
||||
let(:verify) { class_double(Hbc::Verify).as_stubbed_const }
|
||||
let(:error_msg) { "Download Failed" }
|
||||
|
|
|
@ -15,48 +15,42 @@ describe Hbc::CLI do
|
|||
])
|
||||
end
|
||||
|
||||
describe ".process" do
|
||||
context ".process" do
|
||||
let(:noop_command) { double('CLI::Noop') }
|
||||
before {
|
||||
allow(Hbc::CLI).to receive(:lookup_command) { noop_command }
|
||||
allow(noop_command).to receive(:run)
|
||||
}
|
||||
|
||||
it "respects the env variable when choosing what appdir to create" do
|
||||
EnvHelper.with_env_var('HOMEBREW_CASK_OPTS', "--appdir=/custom/appdir") do
|
||||
allow(Hbc).to receive(:init) {
|
||||
expect(Hbc.appdir.to_s).to eq('/custom/appdir')
|
||||
}
|
||||
Hbc::CLI.process('noop')
|
||||
end
|
||||
before do
|
||||
allow(Hbc).to receive(:init)
|
||||
allow(described_class).to receive(:lookup_command).with('noop').and_return(noop_command)
|
||||
allow(noop_command).to receive(:run)
|
||||
end
|
||||
|
||||
# todo: merely invoking init causes an attempt to create the caskroom directory
|
||||
#
|
||||
# it "respects the ENV variable when choosing a non-default Caskroom location" do
|
||||
# EnvHelper.with_env_var 'HOMEBREW_CASK_OPTS', "--caskroom=/custom/caskdir" do
|
||||
# allow(Hbc).to receive(:init) {
|
||||
# expect(Hbc.caskroom.to_s).to eq('/custom/caskdir')
|
||||
# }
|
||||
# Hbc::CLI.process('noop')
|
||||
# end
|
||||
# end
|
||||
|
||||
it "exits with a status of 1 when something goes wrong" do
|
||||
Hbc::CLI.expects(:exit).with(1)
|
||||
Hbc::CLI.expects(:lookup_command).raises(Hbc::CaskError)
|
||||
allow(Hbc).to receive(:init) {
|
||||
shutup {
|
||||
Hbc::CLI.process('noop')
|
||||
}
|
||||
}
|
||||
around do |example|
|
||||
shutup { example.run }
|
||||
end
|
||||
|
||||
it "passes `--version` along to the subcommand" do
|
||||
expect(Hbc::CLI).to receive(:run_command).with(noop_command, '--version')
|
||||
shutup {
|
||||
Hbc::CLI.process(['noop', '--version'])
|
||||
}
|
||||
expect(described_class).to receive(:run_command).with(noop_command, '--version')
|
||||
described_class.process(%w[noop --version])
|
||||
end
|
||||
|
||||
it "respects the env variable when choosing what appdir to create" do
|
||||
EnvHelper.with_env_var('HOMEBREW_CASK_OPTS', "--appdir=/custom/appdir") do
|
||||
expect(Hbc).to receive(:appdir=).with(Pathname('/custom/appdir'))
|
||||
described_class.process('noop')
|
||||
end
|
||||
end
|
||||
|
||||
it "respects the env variable when choosing a non-default Caskroom location" do
|
||||
EnvHelper.with_env_var 'HOMEBREW_CASK_OPTS', "--caskroom=/custom/caskdir" do
|
||||
expect(Hbc).to receive(:caskroom=).with(Pathname('/custom/caskdir'))
|
||||
described_class.process('noop')
|
||||
end
|
||||
end
|
||||
|
||||
it "exits with a status of 1 when something goes wrong" do
|
||||
allow(described_class).to receive(:lookup_command).and_raise(Hbc::CaskError)
|
||||
expect(described_class).to receive(:exit).with(1)
|
||||
described_class.process('noop')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ describe 'download strategies' do
|
|||
let(:url) { 'http://example.com/cask.dmg' }
|
||||
let(:url_options) { Hash.new }
|
||||
let(:cask) {
|
||||
class_double(Hbc::Cask,
|
||||
instance_double(Hbc::Cask,
|
||||
:token => 'some-cask',
|
||||
:url => Hbc::URL.new(url, url_options),
|
||||
:version => '1.2.3.4'
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require 'pathname'
|
||||
|
||||
if ENV['COVERAGE']
|
||||
require 'coveralls'
|
||||
Coveralls.wear_merged!
|
||||
|
|
|
@ -33,8 +33,7 @@ describe Hbc::Artifact::App do
|
|||
end
|
||||
|
||||
it "works with an application in a subdir" do
|
||||
AltSubDirCask = Class.new(Hbc::Cask)
|
||||
AltSubDirCask.class_eval do
|
||||
subdir_cask = Hbc::Cask.new('subdir') do
|
||||
url TestHelper.local_binary_url('caffeine.zip')
|
||||
homepage 'http://example.com/local-caffeine'
|
||||
version '1.2.3'
|
||||
|
@ -43,9 +42,7 @@ describe Hbc::Artifact::App do
|
|||
end
|
||||
|
||||
begin
|
||||
subdir_cask = AltSubDirCask.new.tap do |cask|
|
||||
TestHelper.install_without_artifacts(cask)
|
||||
end
|
||||
TestHelper.install_without_artifacts(subdir_cask)
|
||||
|
||||
appsubdir = subdir_cask.staged_path.join('subdir').tap(&:mkpath)
|
||||
FileUtils.mv(subdir_cask.staged_path.join('Caffeine.app'), appsubdir)
|
||||
|
|
|
@ -19,8 +19,7 @@ describe Hbc::Artifact::App do
|
|||
end
|
||||
|
||||
it "works with an application in a subdir" do
|
||||
SubDirCask = Class.new(Hbc::Cask)
|
||||
SubDirCask.class_eval do
|
||||
subdir_cask = Hbc::Cask.new('subdir') do
|
||||
url TestHelper.local_binary_url('caffeine.zip')
|
||||
homepage 'http://example.com/local-caffeine'
|
||||
version '1.2.3'
|
||||
|
@ -29,9 +28,7 @@ describe Hbc::Artifact::App do
|
|||
end
|
||||
|
||||
begin
|
||||
subdir_cask = SubDirCask.new.tap do |cask|
|
||||
TestHelper.install_without_artifacts(cask)
|
||||
end
|
||||
TestHelper.install_without_artifacts(subdir_cask)
|
||||
|
||||
appsubdir = subdir_cask.staged_path.join('subdir').tap(&:mkpath)
|
||||
FileUtils.mv(subdir_cask.staged_path.join('Caffeine.app'), appsubdir)
|
||||
|
|
|
@ -6,15 +6,13 @@ describe Hbc::Artifact::PostflightBlock do
|
|||
called = false
|
||||
yielded_arg = nil
|
||||
|
||||
CaskWithPostflight = Class.new(Hbc::Cask)
|
||||
CaskWithPostflight.class_eval do
|
||||
cask = Hbc::Cask.new('with-postflight') do
|
||||
postflight do |c|
|
||||
called = true
|
||||
yielded_arg = c
|
||||
end
|
||||
end
|
||||
|
||||
cask = CaskWithPostflight.new
|
||||
Hbc::Artifact::PostflightBlock.new(cask).install_phase
|
||||
|
||||
called.must_equal true
|
||||
|
@ -27,15 +25,13 @@ describe Hbc::Artifact::PostflightBlock do
|
|||
called = false
|
||||
yielded_arg = nil
|
||||
|
||||
CaskWithUninstallPostflight = Class.new(Hbc::Cask)
|
||||
CaskWithUninstallPostflight.class_eval do
|
||||
cask = Hbc::Cask.new('with-uninstall-postflight') do
|
||||
uninstall_postflight do |c|
|
||||
called = true
|
||||
yielded_arg = c
|
||||
end
|
||||
end
|
||||
|
||||
cask = CaskWithUninstallPostflight.new
|
||||
Hbc::Artifact::PostflightBlock.new(cask).uninstall_phase
|
||||
|
||||
called.must_equal true
|
||||
|
|
|
@ -6,15 +6,13 @@ describe Hbc::Artifact::PreflightBlock do
|
|||
called = false
|
||||
yielded_arg = nil
|
||||
|
||||
CaskWithPreflight = Class.new(Hbc::Cask)
|
||||
CaskWithPreflight.class_eval do
|
||||
cask = Hbc::Cask.new('with-preflight') do
|
||||
preflight do |c|
|
||||
called = true
|
||||
yielded_arg = c
|
||||
end
|
||||
end
|
||||
|
||||
cask = CaskWithPreflight.new
|
||||
Hbc::Artifact::PreflightBlock.new(cask).install_phase
|
||||
|
||||
called.must_equal true
|
||||
|
@ -27,15 +25,13 @@ describe Hbc::Artifact::PreflightBlock do
|
|||
called = false
|
||||
yielded_arg = nil
|
||||
|
||||
CaskWithUninstallPreflight = Class.new(Hbc::Cask)
|
||||
CaskWithUninstallPreflight.class_eval do
|
||||
cask = Hbc::Cask.new('with-uninstall-preflight') do
|
||||
uninstall_preflight do |c|
|
||||
called = true
|
||||
yielded_arg = c
|
||||
end
|
||||
end
|
||||
|
||||
cask = CaskWithUninstallPreflight.new
|
||||
Hbc::Artifact::PreflightBlock.new(cask).uninstall_phase
|
||||
|
||||
called.must_equal true
|
||||
|
|
|
@ -20,8 +20,7 @@ describe Hbc::Artifact::App do
|
|||
end
|
||||
|
||||
it "works with an application in a subdir" do
|
||||
AltSubDirTwoAppsCask = Class.new(Hbc::Cask)
|
||||
AltSubDirTwoAppsCask.class_eval do
|
||||
subdir_cask = Hbc::Cask.new('alt-subdir-two-apps') do
|
||||
url TestHelper.local_binary_url('caffeine.zip')
|
||||
homepage 'http://example.com/local-caffeine'
|
||||
version '1.2.3'
|
||||
|
@ -31,9 +30,7 @@ describe Hbc::Artifact::App do
|
|||
end
|
||||
|
||||
begin
|
||||
subdir_cask = AltSubDirTwoAppsCask.new.tap do |cask|
|
||||
TestHelper.install_without_artifacts(cask)
|
||||
end
|
||||
TestHelper.install_without_artifacts(subdir_cask)
|
||||
|
||||
appsubdir = subdir_cask.staged_path.join('subdir').tap(&:mkpath)
|
||||
FileUtils.mv(subdir_cask.staged_path.join('Caffeine.app'), appsubdir)
|
||||
|
|
|
@ -2,13 +2,11 @@ require 'test_helper'
|
|||
|
||||
describe Hbc::Container::Naked do
|
||||
it "saves files with spaces in them from uris with encoded spaces" do
|
||||
SpaceyCask = Class.new(Hbc::Cask)
|
||||
SpaceyCask.class_eval do
|
||||
cask = Hbc::Cask.new('spacey') do
|
||||
url 'http://example.com/kevin%20spacey.pkg'
|
||||
version '1.2'
|
||||
end
|
||||
|
||||
cask = SpaceyCask.new
|
||||
path = '/tmp/downloads/kevin-spacey-1.2.pkg'
|
||||
expected_destination = cask.staged_path.join('kevin spacey.pkg')
|
||||
expected_command = ['/usr/bin/ditto', '--', path, expected_destination]
|
||||
|
|
|
@ -9,12 +9,11 @@ describe Hbc::DSL do
|
|||
end
|
||||
|
||||
describe "when a Cask includes an unknown method" do
|
||||
UnexpectedMethodCask = Class.new(Hbc::Cask)
|
||||
attempt_unknown_method = nil
|
||||
|
||||
before do
|
||||
attempt_unknown_method = lambda {
|
||||
UnexpectedMethodCask.class_eval do
|
||||
Hbc::Cask.new('unexpected-method-cask') do
|
||||
future_feature :not_yet_on_your_machine
|
||||
end
|
||||
}
|
||||
|
@ -48,14 +47,13 @@ describe Hbc::DSL do
|
|||
it "requires a valid header format" do
|
||||
err = lambda {
|
||||
invalid_cask = Hbc.load('invalid/invalid-header-format')
|
||||
}.must_raise(Hbc::CaskHeaderParseError)
|
||||
err.message.must_include 'Bad header line: parse failed'
|
||||
}.must_raise(SyntaxError)
|
||||
end
|
||||
|
||||
it "requires the header token to match the file name" do
|
||||
err = lambda {
|
||||
invalid_cask = Hbc.load('invalid/invalid-header-token-mismatch')
|
||||
}.must_raise(Hbc::CaskInvalidError)
|
||||
}.must_raise(Hbc::CaskTokenDoesNotMatchError)
|
||||
err.message.must_include 'Bad header line:'
|
||||
err.message.must_include 'does not match file name'
|
||||
end
|
||||
|
@ -70,105 +68,91 @@ describe Hbc::DSL do
|
|||
|
||||
describe "name stanza" do
|
||||
it "lets you set the full name via a name stanza" do
|
||||
NameCask = Class.new(Hbc::Cask)
|
||||
NameCask.class_eval do
|
||||
cask = Hbc::Cask.new('name-cask') do
|
||||
name 'Proper Name'
|
||||
end
|
||||
instance = NameCask.new
|
||||
instance.full_name.must_equal [
|
||||
'Proper Name',
|
||||
]
|
||||
|
||||
cask.name.must_equal [
|
||||
'Proper Name',
|
||||
]
|
||||
end
|
||||
|
||||
it "Accepts an array value to the name stanza" do
|
||||
ArrayNameCask = Class.new(Hbc::Cask)
|
||||
ArrayNameCask.class_eval do
|
||||
cask = Hbc::Cask.new('array-name-cask') do
|
||||
name ['Proper Name', 'Alternate Name']
|
||||
end
|
||||
instance = ArrayNameCask.new
|
||||
instance.full_name.must_equal [
|
||||
'Proper Name',
|
||||
'Alternate Name',
|
||||
]
|
||||
|
||||
cask.name.must_equal [
|
||||
'Proper Name',
|
||||
'Alternate Name',
|
||||
]
|
||||
end
|
||||
|
||||
it "Accepts multiple name stanzas" do
|
||||
MultiNameCask = Class.new(Hbc::Cask)
|
||||
MultiNameCask.class_eval do
|
||||
cask = Hbc::Cask.new('multi-name-cask') do
|
||||
name 'Proper Name'
|
||||
name 'Alternate Name'
|
||||
end
|
||||
instance = MultiNameCask.new
|
||||
instance.full_name.must_equal [
|
||||
'Proper Name',
|
||||
'Alternate Name',
|
||||
]
|
||||
|
||||
cask.name.must_equal [
|
||||
'Proper Name',
|
||||
'Alternate Name',
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "sha256 stanza" do
|
||||
it "lets you set checksum via sha256" do
|
||||
ChecksumCask = Class.new(Hbc::Cask)
|
||||
ChecksumCask.class_eval do
|
||||
cask = Hbc::Cask.new('checksum-cask') do
|
||||
sha256 'imasha2'
|
||||
end
|
||||
instance = ChecksumCask.new
|
||||
instance.sha256.must_equal 'imasha2'
|
||||
|
||||
cask.sha256.must_equal 'imasha2'
|
||||
end
|
||||
end
|
||||
|
||||
describe "app stanza" do
|
||||
it "allows you to specify app stanzas" do
|
||||
CaskWithApps = Class.new(Hbc::Cask)
|
||||
CaskWithApps.class_eval do
|
||||
cask = Hbc::Cask.new('cask-with-apps') do
|
||||
app 'Foo.app'
|
||||
app 'Bar.app'
|
||||
end
|
||||
|
||||
instance = CaskWithApps.new
|
||||
Array(instance.artifacts[:app]).must_equal [['Foo.app'], ['Bar.app']]
|
||||
Array(cask.artifacts[:app]).must_equal [['Foo.app'], ['Bar.app']]
|
||||
end
|
||||
|
||||
it "allow app stanzas to be empty" do
|
||||
CaskWithNoApps = Class.new(Hbc::Cask)
|
||||
|
||||
instance = CaskWithNoApps.new
|
||||
Array(instance.artifacts[:app]).must_equal %w[]
|
||||
cask = Hbc::Cask.new('cask-with-no-apps')
|
||||
Array(cask.artifacts[:app]).must_equal %w[]
|
||||
end
|
||||
end
|
||||
|
||||
describe "caveats stanza" do
|
||||
it "allows caveats to be specified via a method define" do
|
||||
PlainCask = Class.new(Hbc::Cask)
|
||||
cask = Hbc::Cask.new('plain-cask')
|
||||
|
||||
instance = PlainCask.new
|
||||
cask.caveats.must_be :empty?
|
||||
|
||||
instance.caveats.must_be :empty?
|
||||
|
||||
CaskWithCaveats = Class.new(Hbc::Cask)
|
||||
CaskWithCaveats.class_eval do
|
||||
cask = Hbc::Cask.new('cask-with-caveats') do
|
||||
def caveats; <<-EOS.undent
|
||||
When you install this Cask, you probably want to know this.
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
instance = CaskWithCaveats.new
|
||||
|
||||
instance.caveats.must_equal "When you install this Cask, you probably want to know this.\n"
|
||||
cask.caveats.must_equal "When you install this Cask, you probably want to know this.\n"
|
||||
end
|
||||
end
|
||||
|
||||
describe "pkg stanza" do
|
||||
it "allows installable pkgs to be specified" do
|
||||
CaskWithPkgs = Class.new(Hbc::Cask)
|
||||
CaskWithPkgs.class_eval do
|
||||
cask = Hbc::Cask.new('cask-with-pkgs') do
|
||||
pkg 'Foo.pkg'
|
||||
pkg 'Bar.pkg'
|
||||
end
|
||||
|
||||
instance = CaskWithPkgs.new
|
||||
Array(instance.artifacts[:pkg]).must_equal [['Foo.pkg'], ['Bar.pkg']]
|
||||
Array(cask.artifacts[:pkg]).must_equal [['Foo.pkg'], ['Bar.pkg']]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,35 +5,23 @@ describe "Cask" do
|
|||
it "returns an instance of the Cask for the given token" do
|
||||
c = Hbc.load("adium")
|
||||
c.must_be_kind_of(Hbc::Cask)
|
||||
c.must_be_instance_of(KlassPrefixAdium)
|
||||
c.token.must_equal('adium')
|
||||
end
|
||||
|
||||
it "returns an instance of the Cask from a specific file location" do
|
||||
# defensive constant cleanup is required because Cask
|
||||
# classes may already be loaded due to audit test
|
||||
begin
|
||||
Object.class_eval{remove_const :KlassPrefixDia}
|
||||
rescue
|
||||
end
|
||||
location = File.expand_path('./Casks/dia.rb')
|
||||
c = Hbc.load(location)
|
||||
c.must_be_kind_of(Hbc::Cask)
|
||||
c.must_be_instance_of(KlassPrefixDia)
|
||||
Object.class_eval{remove_const :KlassPrefixDia}
|
||||
c.token.must_equal('dia')
|
||||
end
|
||||
|
||||
it "returns an instance of the Cask from a url" do
|
||||
begin
|
||||
Object.class_eval{remove_const :KlassPrefixDia}
|
||||
rescue
|
||||
end
|
||||
url = "file://" + File.expand_path('./Casks/dia.rb')
|
||||
c = shutup do
|
||||
Hbc.load(url)
|
||||
end
|
||||
c.must_be_kind_of(Hbc::Cask)
|
||||
c.must_be_instance_of(KlassPrefixDia)
|
||||
Object.class_eval{remove_const :KlassPrefixDia}
|
||||
c.token.must_equal('dia')
|
||||
end
|
||||
|
||||
it "raises an error when failing to download a Cask from a url" do
|
||||
|
@ -46,19 +34,14 @@ describe "Cask" do
|
|||
end
|
||||
|
||||
it "returns an instance of the Cask from a relative file location" do
|
||||
begin
|
||||
Object.class_eval{remove_const :KlassPrefixBbedit}
|
||||
rescue
|
||||
end
|
||||
c = Hbc.load("./Casks/bbedit.rb")
|
||||
c.must_be_kind_of(Hbc::Cask)
|
||||
c.must_be_instance_of(KlassPrefixBbedit)
|
||||
Object.class_eval{remove_const :KlassPrefixBbedit}
|
||||
c.token.must_equal('bbedit')
|
||||
end
|
||||
|
||||
it "uses exact match when loading by token" do
|
||||
Hbc.load('test-opera').must_be_instance_of(KlassPrefixTestOpera)
|
||||
Hbc.load('test-opera-mail').must_be_instance_of(KlassPrefixTestOperaMail)
|
||||
Hbc.load('test-opera').token.must_equal('test-opera')
|
||||
Hbc.load('test-opera-mail').token.must_equal('test-opera-mail')
|
||||
end
|
||||
|
||||
it "raises an error when attempting to load a Cask that doesn't exist" do
|
||||
|
@ -72,19 +55,7 @@ describe "Cask" do
|
|||
it "returns a token for every Cask" do
|
||||
all_cask_tokens = Hbc.all_tokens
|
||||
all_cask_tokens.count.must_be :>, 20
|
||||
all_cask_tokens.each { |cask| cask.must_be_kind_of String }
|
||||
end
|
||||
end
|
||||
|
||||
describe "token" do
|
||||
it "converts a class constant to a token-style dashed string" do
|
||||
KlassPrefixPascalCasedConstant = Class.new(Hbc::Cask)
|
||||
KlassPrefixPascalCasedConstant.token.must_equal 'pascal-cased-constant'
|
||||
end
|
||||
|
||||
it "properly dasherizes constants with single letters in the middle" do
|
||||
KlassPrefixGamesXChange = Class.new(Hbc::Cask)
|
||||
KlassPrefixGamesXChange.token.must_equal 'games-x-change'
|
||||
all_cask_tokens.each { |token| token.must_be_kind_of String }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'bundler'
|
||||
require 'bundler/setup'
|
||||
require 'pathname'
|
||||
|
||||
if ENV['COVERAGE']
|
||||
require 'coveralls'
|
||||
|
@ -18,11 +19,10 @@ lib_path = brew_cask_path.join('lib')
|
|||
$:.push(lib_path)
|
||||
|
||||
# todo: removeme, this is transitional
|
||||
require "#{brew_cask_path}/spec/support/kernel_at_exit_hacks"
|
||||
require "#{brew_cask_path}/spec/support/homebrew_testing_environment"
|
||||
include HomebrewTestingEnvironment
|
||||
require 'vendor/homebrew-fork/testing_env'
|
||||
|
||||
# force some environment variables
|
||||
ENV['HOMEBREW_NO_EMOJI'] = '1'
|
||||
ENV['HOMEBREW_CASK_OPTS'] = nil
|
||||
|
||||
# todo temporary, copied from old Homebrew, this method is now moved inside a class
|
||||
|
@ -87,7 +87,7 @@ class TestHelper
|
|||
end
|
||||
|
||||
def self.test_cask
|
||||
Hbc.load('basic-cask')
|
||||
@test_cask ||= Hbc.load('basic-cask')
|
||||
end
|
||||
|
||||
def self.fake_fetcher
|
||||
|
|
Loading…
Reference in New Issue