mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Treat every Artifact
instance as a single artifact.
This commit is contained in:
parent
5bcce735dd
commit
53ecdd843f
@ -33,7 +33,7 @@ module Hbc
|
|||||||
# We want to extract nested containers before we
|
# We want to extract nested containers before we
|
||||||
# handle any other artifacts.
|
# handle any other artifacts.
|
||||||
#
|
#
|
||||||
TYPES = [
|
CLASSES = [
|
||||||
PreflightBlock,
|
PreflightBlock,
|
||||||
Uninstall,
|
Uninstall,
|
||||||
NestedContainer,
|
NestedContainer,
|
||||||
@ -60,12 +60,9 @@ module Hbc
|
|||||||
Zap,
|
Zap,
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
def self.for_cask(cask, options = {})
|
def self.for_cask(cask)
|
||||||
odebug "Determining which artifacts are present in Cask #{cask}"
|
odebug "Determining which artifacts are present in Cask #{cask}"
|
||||||
|
CLASSES.flat_map { |klass| klass.for_cask(cask) }
|
||||||
TYPES
|
|
||||||
.select { |klass| klass.me?(cask) }
|
|
||||||
.map { |klass| klass.new(cask, options) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,34 +1,28 @@
|
|||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Base
|
class AbstractArtifact
|
||||||
extend Predicable
|
extend Predicable
|
||||||
|
|
||||||
def self.artifact_name
|
def self.english_name
|
||||||
@artifact_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase
|
@english_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1 \2')
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.artifact_english_name
|
def self.english_article
|
||||||
@artifact_english_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1 \2')
|
@english_article ||= (english_name =~ /^[aeiou]/i) ? "an" : "a"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.artifact_english_article
|
def self.dsl_key
|
||||||
@artifact_english_article ||= (artifact_english_name =~ /^[aeiou]/i) ? "an" : "a"
|
@dsl_key ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase.to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.artifact_dsl_key
|
def self.dirmethod
|
||||||
@artifact_dsl_key ||= artifact_name.to_sym
|
@dirmethod ||= "#{dsl_key}dir".to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.artifact_dirmethod
|
def self.for_cask(cask)
|
||||||
@artifact_dirmethod ||= "#{artifact_name}dir".to_sym
|
cask.artifacts[dsl_key].to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.me?(cask)
|
|
||||||
cask.artifacts[artifact_dsl_key].any?
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :force
|
|
||||||
|
|
||||||
# TODO: this sort of logic would make more sense in dsl.rb, or a
|
# TODO: this sort of logic would make more sense in dsl.rb, or a
|
||||||
# constructor called from dsl.rb, so long as that isn't slow.
|
# constructor called from dsl.rb, so long as that isn't slow.
|
||||||
def self.read_script_arguments(arguments, stanza, default_arguments = {}, override_arguments = {}, key = nil)
|
def self.read_script_arguments(arguments, stanza, default_arguments = {}, override_arguments = {}, key = nil)
|
||||||
@ -63,17 +57,14 @@ module Hbc
|
|||||||
[executable, arguments]
|
[executable, arguments]
|
||||||
end
|
end
|
||||||
|
|
||||||
def summary
|
attr_reader :cask
|
||||||
{}
|
|
||||||
|
def initialize(cask)
|
||||||
|
@cask = cask
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_predicate :force?, :verbose?
|
def to_s
|
||||||
|
"#{summarize} (#{self.class.english_name})"
|
||||||
def initialize(cask, command: SystemCommand, force: false, verbose: false)
|
|
||||||
@cask = cask
|
|
||||||
@command = command
|
|
||||||
@force = force
|
|
||||||
@verbose = verbose
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,39 +1,47 @@
|
|||||||
require "hbc/artifact/base"
|
require "hbc/artifact/abstract_artifact"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class AbstractFlightBlock < Base
|
class AbstractFlightBlock < AbstractArtifact
|
||||||
def self.artifact_dsl_key
|
def self.dsl_key
|
||||||
super.to_s.sub(/_block$/, "").to_sym
|
super.to_s.sub(/_block$/, "").to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.uninstall_artifact_dsl_key
|
def self.uninstall_dsl_key
|
||||||
artifact_dsl_key.to_s.prepend("uninstall_").to_sym
|
dsl_key.to_s.prepend("uninstall_").to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.class_for_dsl_key(dsl_key)
|
def self.for_cask(cask)
|
||||||
Object.const_get("Hbc::DSL::#{dsl_key.to_s.split("_").collect(&:capitalize).join}")
|
[dsl_key, uninstall_dsl_key].flat_map do |key|
|
||||||
|
[*cask.artifacts[key]].map { |block| new(cask, key => block) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.me?(cask)
|
attr_reader :directives
|
||||||
cask.artifacts[artifact_dsl_key].any? ||
|
|
||||||
cask.artifacts[uninstall_artifact_dsl_key].any?
|
def initialize(cask, **directives)
|
||||||
|
super(cask)
|
||||||
|
@directives = directives
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_phase
|
def install_phase(**)
|
||||||
abstract_phase(self.class.artifact_dsl_key)
|
abstract_phase(self.class.dsl_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_phase
|
def uninstall_phase(**)
|
||||||
abstract_phase(self.class.uninstall_artifact_dsl_key)
|
abstract_phase(self.class.uninstall_dsl_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def abstract_phase(dsl_key)
|
def class_for_dsl_key(dsl_key)
|
||||||
@cask.artifacts[dsl_key].each do |block|
|
namespace = self.class.name.to_s.sub(/::.*::.*$/, "")
|
||||||
self.class.class_for_dsl_key(dsl_key).new(@cask).instance_eval(&block)
|
self.class.const_get("#{namespace}::DSL::#{dsl_key.to_s.split("_").collect(&:capitalize).join}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def abstract_phase(dsl_key)
|
||||||
|
return if (block = directives[dsl_key]).nil?
|
||||||
|
class_for_dsl_key(dsl_key).new(cask).instance_eval(&block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
require "pathname"
|
require "pathname"
|
||||||
require "timeout"
|
require "timeout"
|
||||||
|
|
||||||
require "hbc/artifact/base"
|
require "hbc/artifact/abstract_artifact"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class UninstallBase < Base
|
class AbstractUninstall < AbstractArtifact
|
||||||
ORDERED_DIRECTIVES = [
|
ORDERED_DIRECTIVES = [
|
||||||
:early_script,
|
:early_script,
|
||||||
:launchctl,
|
:launchctl,
|
||||||
@ -20,26 +20,33 @@ module Hbc
|
|||||||
:rmdir,
|
:rmdir,
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
def dispatch_uninstall_directives
|
def self.from_args(cask, **directives)
|
||||||
directives_set = @cask.artifacts[stanza]
|
new(cask, directives)
|
||||||
ohai "Running #{stanza} process for #{@cask}; your password may be necessary"
|
|
||||||
|
|
||||||
directives_set.each do |directives|
|
|
||||||
warn_for_unknown_directives(directives)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
ORDERED_DIRECTIVES.each do |directive_sym|
|
attr_reader :directives
|
||||||
directives_set.select { |h| h.key?(directive_sym) }.each do |directives|
|
|
||||||
args = directives[directive_sym]
|
def initialize(cask, directives)
|
||||||
send("uninstall_#{directive_sym}", *(args.is_a?(Hash) ? [args] : args))
|
super(cask)
|
||||||
end
|
@directives = directives
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def dispatch_uninstall_directives(**options)
|
||||||
|
ohai "Running #{stanza} process for #{@cask}; your password may be necessary"
|
||||||
|
|
||||||
|
warn_for_unknown_directives(directives)
|
||||||
|
|
||||||
|
ORDERED_DIRECTIVES.each do |directive_sym|
|
||||||
|
next unless directives.key?(directive_sym)
|
||||||
|
args = directives[directive_sym]
|
||||||
|
send("uninstall_#{directive_sym}", *(args.is_a?(Hash) ? [args] : args), **options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def stanza
|
def stanza
|
||||||
self.class.artifact_dsl_key
|
self.class.dsl_key
|
||||||
end
|
end
|
||||||
|
|
||||||
def warn_for_unknown_directives(directives)
|
def warn_for_unknown_directives(directives)
|
||||||
@ -51,18 +58,18 @@ module Hbc
|
|||||||
# Preserve prior functionality of script which runs first. Should rarely be needed.
|
# Preserve prior functionality of script which runs first. Should rarely be needed.
|
||||||
# :early_script should not delete files, better defer that to :script.
|
# :early_script should not delete files, better defer that to :script.
|
||||||
# If Cask writers never need :early_script it may be removed in the future.
|
# If Cask writers never need :early_script it may be removed in the future.
|
||||||
def uninstall_early_script(directives)
|
def uninstall_early_script(directives, **options)
|
||||||
uninstall_script(directives, directive_name: :early_script)
|
uninstall_script(directives, directive_name: :early_script, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# :launchctl must come before :quit/:signal for cases where app would instantly re-launch
|
# :launchctl must come before :quit/:signal for cases where app would instantly re-launch
|
||||||
def uninstall_launchctl(*services)
|
def uninstall_launchctl(*services, command: nil, **_)
|
||||||
services.each do |service|
|
services.each do |service|
|
||||||
ohai "Removing launchctl service #{service}"
|
ohai "Removing launchctl service #{service}"
|
||||||
[false, true].each do |with_sudo|
|
[false, true].each do |with_sudo|
|
||||||
plist_status = @command.run("/bin/launchctl", args: ["list", service], sudo: with_sudo, print_stderr: false).stdout
|
plist_status = command.run("/bin/launchctl", args: ["list", service], sudo: with_sudo, print_stderr: false).stdout
|
||||||
if plist_status =~ /^\{/
|
if plist_status =~ /^\{/
|
||||||
@command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo)
|
command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo)
|
||||||
sleep 1
|
sleep 1
|
||||||
end
|
end
|
||||||
paths = ["/Library/LaunchAgents/#{service}.plist",
|
paths = ["/Library/LaunchAgents/#{service}.plist",
|
||||||
@ -70,19 +77,19 @@ module Hbc
|
|||||||
paths.each { |elt| elt.prepend(ENV["HOME"]) } unless with_sudo
|
paths.each { |elt| elt.prepend(ENV["HOME"]) } unless with_sudo
|
||||||
paths = paths.map { |elt| Pathname(elt) }.select(&:exist?)
|
paths = paths.map { |elt| Pathname(elt) }.select(&:exist?)
|
||||||
paths.each do |path|
|
paths.each do |path|
|
||||||
@command.run!("/bin/rm", args: ["-f", "--", path], sudo: with_sudo)
|
command.run!("/bin/rm", args: ["-f", "--", path], sudo: with_sudo)
|
||||||
end
|
end
|
||||||
# undocumented and untested: pass a path to uninstall :launchctl
|
# undocumented and untested: pass a path to uninstall :launchctl
|
||||||
next unless Pathname(service).exist?
|
next unless Pathname(service).exist?
|
||||||
@command.run!("/bin/launchctl", args: ["unload", "-w", "--", service], sudo: with_sudo)
|
command.run!("/bin/launchctl", args: ["unload", "-w", "--", service], sudo: with_sudo)
|
||||||
@command.run!("/bin/rm", args: ["-f", "--", service], sudo: with_sudo)
|
command.run!("/bin/rm", args: ["-f", "--", service], sudo: with_sudo)
|
||||||
sleep 1
|
sleep 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def running_processes(bundle_id)
|
def running_processes(bundle_id, command: nil)
|
||||||
@command.run!("/bin/launchctl", args: ["list"]).stdout.lines
|
command.run!("/bin/launchctl", args: ["list"]).stdout.lines
|
||||||
.map { |line| line.chomp.split("\t") }
|
.map { |line| line.chomp.split("\t") }
|
||||||
.map { |pid, state, id| [pid.to_i, state.to_i, id] }
|
.map { |pid, state, id| [pid.to_i, state.to_i, id] }
|
||||||
.select do |fields|
|
.select do |fields|
|
||||||
@ -92,16 +99,16 @@ module Hbc
|
|||||||
end
|
end
|
||||||
|
|
||||||
# :quit/:signal must come before :kext so the kext will not be in use by a running process
|
# :quit/:signal must come before :kext so the kext will not be in use by a running process
|
||||||
def uninstall_quit(*bundle_ids)
|
def uninstall_quit(*bundle_ids, command: nil, **_)
|
||||||
bundle_ids.each do |bundle_id|
|
bundle_ids.each do |bundle_id|
|
||||||
ohai "Quitting application ID #{bundle_id}"
|
ohai "Quitting application ID #{bundle_id}"
|
||||||
next if running_processes(bundle_id).empty?
|
next if running_processes(bundle_id, command: command).empty?
|
||||||
@command.run!("/usr/bin/osascript", args: ["-e", %Q(tell application id "#{bundle_id}" to quit)], sudo: true)
|
command.run!("/usr/bin/osascript", args: ["-e", %Q(tell application id "#{bundle_id}" to quit)], sudo: true)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Timeout.timeout(3) do
|
Timeout.timeout(3) do
|
||||||
Kernel.loop do
|
Kernel.loop do
|
||||||
break if running_processes(bundle_id).empty?
|
break if running_processes(bundle_id, command: command).empty?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue Timeout::Error
|
rescue Timeout::Error
|
||||||
@ -111,15 +118,15 @@ module Hbc
|
|||||||
end
|
end
|
||||||
|
|
||||||
# :signal should come after :quit so it can be used as a backup when :quit fails
|
# :signal should come after :quit so it can be used as a backup when :quit fails
|
||||||
def uninstall_signal(*signals)
|
def uninstall_signal(*signals, **options)
|
||||||
signals.flatten.each_slice(2) do |pair|
|
signals.flatten.each_slice(2) do |pair|
|
||||||
unless pair.size == 2
|
unless pair.size == 2
|
||||||
raise CaskInvalidError.new(@cask, "Each #{stanza} :signal must consist of 2 elements.")
|
raise CaskInvalidError.new(cask, "Each #{stanza} :signal must consist of 2 elements.")
|
||||||
end
|
end
|
||||||
|
|
||||||
signal, bundle_id = pair
|
signal, bundle_id = pair
|
||||||
ohai "Signalling '#{signal}' to application ID '#{bundle_id}'"
|
ohai "Signalling '#{signal}' to application ID '#{bundle_id}'"
|
||||||
pids = running_processes(bundle_id).map(&:first)
|
pids = running_processes(bundle_id, **options).map(&:first)
|
||||||
next unless pids.any?
|
next unless pids.any?
|
||||||
# Note that unlike :quit, signals are sent from the current user (not
|
# Note that unlike :quit, signals are sent from the current user (not
|
||||||
# upgraded to the superuser). This is a todo item for the future, but
|
# upgraded to the superuser). This is a todo item for the future, but
|
||||||
@ -133,10 +140,10 @@ module Hbc
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_login_item(*login_items)
|
def uninstall_login_item(*login_items, command: nil, **_)
|
||||||
login_items.each do |name|
|
login_items.each do |name|
|
||||||
ohai "Removing login item #{name}"
|
ohai "Removing login item #{name}"
|
||||||
@command.run!("/usr/bin/osascript",
|
command.run!("/usr/bin/osascript",
|
||||||
args: ["-e", %Q(tell application "System Events" to delete every login item whose name is "#{name}")],
|
args: ["-e", %Q(tell application "System Events" to delete every login item whose name is "#{name}")],
|
||||||
sudo: false)
|
sudo: false)
|
||||||
sleep 1
|
sleep 1
|
||||||
@ -144,23 +151,24 @@ module Hbc
|
|||||||
end
|
end
|
||||||
|
|
||||||
# :kext should be unloaded before attempting to delete the relevant file
|
# :kext should be unloaded before attempting to delete the relevant file
|
||||||
def uninstall_kext(*kexts)
|
def uninstall_kext(*kexts, command: nil, **_)
|
||||||
kexts.each do |kext|
|
kexts.each do |kext|
|
||||||
ohai "Unloading kernel extension #{kext}"
|
ohai "Unloading kernel extension #{kext}"
|
||||||
is_loaded = @command.run!("/usr/sbin/kextstat", args: ["-l", "-b", kext], sudo: true).stdout
|
is_loaded = command.run!("/usr/sbin/kextstat", args: ["-l", "-b", kext], sudo: true).stdout
|
||||||
if is_loaded.length > 1
|
if is_loaded.length > 1
|
||||||
@command.run!("/sbin/kextunload", args: ["-b", kext], sudo: true)
|
command.run!("/sbin/kextunload", args: ["-b", kext], sudo: true)
|
||||||
sleep 1
|
sleep 1
|
||||||
end
|
end
|
||||||
@command.run!("/usr/sbin/kextfind", args: ["-b", kext], sudo: true).stdout.chomp.lines.each do |kext_path|
|
command.run!("/usr/sbin/kextfind", args: ["-b", kext], sudo: true).stdout.chomp.lines.each do |kext_path|
|
||||||
ohai "Removing kernel extension #{kext_path}"
|
ohai "Removing kernel extension #{kext_path}"
|
||||||
@command.run!("/bin/rm", args: ["-rf", kext_path], sudo: true)
|
command.run!("/bin/rm", args: ["-rf", kext_path], sudo: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# :script must come before :pkgutil, :delete, or :trash so that the script file is not already deleted
|
# :script must come before :pkgutil, :delete, or :trash so that the script file is not already deleted
|
||||||
def uninstall_script(directives, directive_name: :script)
|
def uninstall_script(directives, directive_name: :script, force: false, command: nil, **_)
|
||||||
|
# TODO: Create a common `Script` class to run this and Artifact::Installer.
|
||||||
executable, script_arguments = self.class.read_script_arguments(directives,
|
executable, script_arguments = self.class.read_script_arguments(directives,
|
||||||
"uninstall",
|
"uninstall",
|
||||||
{ must_succeed: true, sudo: false },
|
{ must_succeed: true, sudo: false },
|
||||||
@ -168,25 +176,25 @@ module Hbc
|
|||||||
directive_name)
|
directive_name)
|
||||||
|
|
||||||
ohai "Running uninstall script #{executable}"
|
ohai "Running uninstall script #{executable}"
|
||||||
raise CaskInvalidError.new(@cask, "#{stanza} :#{directive_name} without :executable.") if executable.nil?
|
raise CaskInvalidError.new(cask, "#{stanza} :#{directive_name} without :executable.") if executable.nil?
|
||||||
executable_path = @cask.staged_path.join(executable)
|
executable_path = cask.staged_path.join(executable)
|
||||||
|
|
||||||
unless executable_path.exist?
|
unless executable_path.exist?
|
||||||
message = "uninstall script #{executable} does not exist"
|
message = "uninstall script #{executable} does not exist"
|
||||||
raise CaskError, "#{message}." unless force?
|
raise CaskError, "#{message}." unless force
|
||||||
opoo "#{message}, skipping."
|
opoo "#{message}, skipping."
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@command.run("/bin/chmod", args: ["--", "+x", executable_path])
|
command.run("/bin/chmod", args: ["--", "+x", executable_path])
|
||||||
@command.run(executable_path, script_arguments)
|
command.run(executable_path, script_arguments)
|
||||||
sleep 1
|
sleep 1
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_pkgutil(*pkgs)
|
def uninstall_pkgutil(*pkgs, command: nil, **_)
|
||||||
ohai "Uninstalling packages:"
|
ohai "Uninstalling packages:"
|
||||||
pkgs.each do |regex|
|
pkgs.each do |regex|
|
||||||
Hbc::Pkg.all_matching(regex, @command).each do |pkg|
|
Hbc::Pkg.all_matching(regex, command).each do |pkg|
|
||||||
puts pkg.package_id
|
puts pkg.package_id
|
||||||
pkg.uninstall
|
pkg.uninstall
|
||||||
end
|
end
|
||||||
@ -215,28 +223,28 @@ module Hbc
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_delete(*paths)
|
def uninstall_delete(*paths, command: nil, **_)
|
||||||
return if paths.empty?
|
return if paths.empty?
|
||||||
|
|
||||||
ohai "Removing files:"
|
ohai "Removing files:"
|
||||||
each_resolved_path(:delete, paths) do |path, resolved_paths|
|
each_resolved_path(:delete, paths) do |path, resolved_paths|
|
||||||
puts path
|
puts path
|
||||||
@command.run!("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "-r", "-f", "--"], input: resolved_paths.join("\0"), sudo: true)
|
command.run!("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "-r", "-f", "--"], input: resolved_paths.join("\0"), sudo: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_trash(*paths)
|
def uninstall_trash(*paths, **options)
|
||||||
return if paths.empty?
|
return if paths.empty?
|
||||||
|
|
||||||
resolved_paths = each_resolved_path(:trash, paths).to_a
|
resolved_paths = each_resolved_path(:trash, paths).to_a
|
||||||
|
|
||||||
ohai "Trashing files:"
|
ohai "Trashing files:"
|
||||||
puts resolved_paths.map(&:first)
|
puts resolved_paths.map(&:first)
|
||||||
trash_paths(*resolved_paths.flat_map(&:last))
|
trash_paths(*resolved_paths.flat_map(&:last), **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def trash_paths(*paths)
|
def trash_paths(*paths, command: nil, **_)
|
||||||
@command.run!("/usr/bin/osascript", args: ["-e", <<-'EOS'.undent, *paths])
|
command.run!("/usr/bin/osascript", args: ["-e", <<-'EOS'.undent, *paths])
|
||||||
on run argv
|
on run argv
|
||||||
repeat with i from 1 to (count argv)
|
repeat with i from 1 to (count argv)
|
||||||
set item i of argv to (item i of argv as POSIX file)
|
set item i of argv to (item i of argv as POSIX file)
|
||||||
@ -260,7 +268,7 @@ module Hbc
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_rmdir(*directories)
|
def uninstall_rmdir(*directories, command: nil, **_)
|
||||||
return if directories.empty?
|
return if directories.empty?
|
||||||
|
|
||||||
ohai "Removing directories if empty:"
|
ohai "Removing directories if empty:"
|
||||||
@ -268,10 +276,10 @@ module Hbc
|
|||||||
puts path
|
puts path
|
||||||
resolved_paths.select(&:directory?).each do |resolved_path|
|
resolved_paths.select(&:directory?).each do |resolved_path|
|
||||||
if (ds_store = resolved_path.join(".DS_Store")).exist?
|
if (ds_store = resolved_path.join(".DS_Store")).exist?
|
||||||
@command.run!("/bin/rm", args: ["-f", "--", ds_store], sudo: true, print_stderr: false)
|
command.run!("/bin/rm", args: ["-f", "--", ds_store], sudo: true, print_stderr: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
@command.run("/bin/rmdir", args: ["--", resolved_path], sudo: true, print_stderr: false)
|
command.run("/bin/rmdir", args: ["--", resolved_path], sudo: true, print_stderr: false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -5,21 +5,32 @@ require "hbc/utils/hash_validator"
|
|||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Artifact < Moved
|
class Artifact < Moved
|
||||||
def self.artifact_english_name
|
def self.english_name
|
||||||
"Generic Artifact"
|
"Generic Artifact"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.artifact_dirmethod
|
def self.from_args(cask, *args)
|
||||||
:appdir
|
source_string, target_hash = args
|
||||||
|
|
||||||
|
if source_string.nil?
|
||||||
|
raise CaskInvalidError.new(cask.token, "no source given for #{english_name}")
|
||||||
|
end
|
||||||
|
|
||||||
|
unless target_hash.is_a?(Hash)
|
||||||
|
raise CaskInvalidError.new(cask.token, "target required for #{english_name} '#{source_string}'")
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_specification(artifact_spec)
|
|
||||||
source_string, target_hash = artifact_spec
|
|
||||||
raise CaskInvalidError.new(@cask.token, "no source given for artifact") if source_string.nil?
|
|
||||||
@source = @cask.staged_path.join(source_string)
|
|
||||||
raise CaskInvalidError.new(@cask.token, "target required for generic artifact #{source_string}") unless target_hash.is_a?(Hash)
|
|
||||||
target_hash.extend(HashValidator).assert_valid_keys(:target)
|
target_hash.extend(HashValidator).assert_valid_keys(:target)
|
||||||
@target = Pathname.new(target_hash[:target])
|
|
||||||
|
new(cask, source_string, **target_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.resolve_target(target)
|
||||||
|
Pathname(target)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(cask, source, target: nil)
|
||||||
|
super(cask, source, target: target)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,13 +3,13 @@ require "hbc/artifact/symlinked"
|
|||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Binary < Symlinked
|
class Binary < Symlinked
|
||||||
def link
|
def link(command: nil, **options)
|
||||||
super
|
super(command: command, **options)
|
||||||
return if source.executable?
|
return if source.executable?
|
||||||
if source.writable?
|
if source.writable?
|
||||||
FileUtils.chmod "+x", source
|
FileUtils.chmod "+x", source
|
||||||
else
|
else
|
||||||
@command.run!("/bin/chmod", args: ["+x", source], sudo: true)
|
command.run!("/bin/chmod", args: ["+x", source], sudo: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,30 +1,77 @@
|
|||||||
require "hbc/artifact/base"
|
require "hbc/artifact/abstract_artifact"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Installer < Base
|
class Installer < AbstractArtifact
|
||||||
def install_phase
|
VALID_KEYS = Set.new [
|
||||||
@cask.artifacts[self.class.artifact_dsl_key].each do |artifact|
|
:manual,
|
||||||
if artifact.manual
|
:script,
|
||||||
|
]
|
||||||
|
|
||||||
|
module ManualInstaller
|
||||||
|
def install_phase(**)
|
||||||
puts <<-EOS.undent
|
puts <<-EOS.undent
|
||||||
To complete the installation of Cask #{@cask}, you must also
|
To complete the installation of Cask #{cask}, you must also
|
||||||
run the installer at
|
run the installer at
|
||||||
|
|
||||||
'#{@cask.staged_path.join(artifact.manual)}'
|
'#{path}'
|
||||||
|
|
||||||
EOS
|
EOS
|
||||||
else
|
|
||||||
executable, script_arguments = self.class.read_script_arguments(artifact.script,
|
|
||||||
self.class.artifact_dsl_key.to_s,
|
|
||||||
{ must_succeed: true, sudo: false },
|
|
||||||
print_stdout: true)
|
|
||||||
ohai "Running #{self.class.artifact_dsl_key} script #{executable}"
|
|
||||||
raise CaskInvalidError.new(@cask, "#{self.class.artifact_dsl_key} missing executable") if executable.nil?
|
|
||||||
executable_path = @cask.staged_path.join(executable)
|
|
||||||
@command.run("/bin/chmod", args: ["--", "+x", executable_path]) if File.exist?(executable_path)
|
|
||||||
@command.run(executable_path, script_arguments)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module ScriptInstaller
|
||||||
|
def install_phase(command: nil, **_)
|
||||||
|
ohai "Running #{self.class.dsl_key} script '#{path.relative_path_from(cask.staged_path)}'"
|
||||||
|
FileUtils.chmod "+x", path unless path.executable?
|
||||||
|
command.run(path, **args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_args(cask, **args)
|
||||||
|
raise CaskInvalidError.new(cask, "'installer' stanza requires an argument.") if args.empty?
|
||||||
|
|
||||||
|
if args.key?(:script) && !args[:script].respond_to?(:key?)
|
||||||
|
if args.key?(:executable)
|
||||||
|
raise CaskInvalidError.new(cask, "'installer' stanza gave arguments for both :script and :executable.")
|
||||||
|
end
|
||||||
|
|
||||||
|
args[:executable] = args[:script]
|
||||||
|
args.delete(:script)
|
||||||
|
args = { script: args }
|
||||||
|
end
|
||||||
|
|
||||||
|
unless args.keys.count == 1
|
||||||
|
raise CaskInvalidError.new(cask, "invalid 'installer' stanza: Only one of #{VALID_KEYS.inspect} is permitted.")
|
||||||
|
end
|
||||||
|
|
||||||
|
args.extend(HashValidator).assert_valid_keys(*VALID_KEYS)
|
||||||
|
new(cask, **args)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :path, :args
|
||||||
|
|
||||||
|
def initialize(cask, **args)
|
||||||
|
super(cask)
|
||||||
|
|
||||||
|
if args.key?(:manual)
|
||||||
|
@path = cask.staged_path.join(args[:manual])
|
||||||
|
@args = []
|
||||||
|
extend(ManualInstaller)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
path, @args = self.class.read_script_arguments(
|
||||||
|
args[:script], self.class.dsl_key.to_s, { must_succeed: true, sudo: false }, print_stdout: true
|
||||||
|
)
|
||||||
|
raise CaskInvalidError.new(cask, "#{self.class.dsl_key} missing executable") if path.nil?
|
||||||
|
|
||||||
|
path = Pathname(path)
|
||||||
|
@path = path.absolute? ? path : cask.staged_path.join(path)
|
||||||
|
extend(ScriptInstaller)
|
||||||
|
end
|
||||||
|
|
||||||
|
def summarize
|
||||||
|
path.relative_path_from(cask.staged_path).to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,63 +4,61 @@ module Hbc
|
|||||||
module Artifact
|
module Artifact
|
||||||
class Moved < Relocated
|
class Moved < Relocated
|
||||||
def self.english_description
|
def self.english_description
|
||||||
"#{artifact_english_name}s"
|
"#{english_name}s"
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_phase
|
def install_phase(**options)
|
||||||
each_artifact(&method(:move))
|
move(**options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_phase
|
def uninstall_phase(**options)
|
||||||
each_artifact(&method(:delete))
|
delete(**options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def summarize_installed
|
||||||
|
if target.exist?
|
||||||
|
"#{printable_target} (#{target.abv})"
|
||||||
|
else
|
||||||
|
Formatter.error(printable_target, label: "Missing #{self.class.english_name}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def move
|
def move(force: false, command: nil, **options)
|
||||||
if Utils.path_occupied?(target)
|
if Utils.path_occupied?(target)
|
||||||
message = "It seems there is already #{self.class.artifact_english_article} #{self.class.artifact_english_name} at '#{target}'"
|
message = "It seems there is already #{self.class.english_article} #{self.class.english_name} at '#{target}'"
|
||||||
raise CaskError, "#{message}." unless force?
|
raise CaskError, "#{message}." unless force
|
||||||
opoo "#{message}; overwriting."
|
opoo "#{message}; overwriting."
|
||||||
delete
|
delete(force: force, command: command, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
unless source.exist?
|
unless source.exist?
|
||||||
raise CaskError, "It seems the #{self.class.artifact_english_name} source '#{source}' is not there."
|
raise CaskError, "It seems the #{self.class.english_name} source '#{source}' is not there."
|
||||||
end
|
end
|
||||||
|
|
||||||
ohai "Moving #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'."
|
ohai "Moving #{self.class.english_name} '#{source.basename}' to '#{target}'."
|
||||||
target.dirname.mkpath
|
target.dirname.mkpath
|
||||||
|
|
||||||
if target.parent.writable?
|
if target.parent.writable?
|
||||||
FileUtils.move(source, target)
|
FileUtils.move(source, target)
|
||||||
else
|
else
|
||||||
SystemCommand.run("/bin/mv", args: [source, target], sudo: true)
|
command.run("/bin/mv", args: [source, target], sudo: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_altname_metadata target, source.basename.to_s
|
add_altname_metadata(target, source.basename, command: command)
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete
|
def delete(force: false, command: nil, **_)
|
||||||
ohai "Removing #{self.class.artifact_english_name} '#{target}'."
|
ohai "Removing #{self.class.english_name} '#{target}'."
|
||||||
raise CaskError, "Cannot remove undeletable #{self.class.artifact_english_name}." if MacOS.undeletable?(target)
|
raise CaskError, "Cannot remove undeletable #{self.class.english_name}." if MacOS.undeletable?(target)
|
||||||
|
|
||||||
return unless Utils.path_occupied?(target)
|
return unless Utils.path_occupied?(target)
|
||||||
|
|
||||||
if target.parent.writable? && !force
|
if target.parent.writable? && !force
|
||||||
target.rmtree
|
target.rmtree
|
||||||
else
|
else
|
||||||
Utils.gain_permissions_remove(target, command: @command)
|
Utils.gain_permissions_remove(target, command: command)
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def summarize_artifact(artifact_spec)
|
|
||||||
load_specification artifact_spec
|
|
||||||
|
|
||||||
if target.exist?
|
|
||||||
"#{printable_target} (#{target.abv})"
|
|
||||||
else
|
|
||||||
Formatter.error(printable_target, label: "Missing #{self.class.artifact_english_name}")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,23 +1,31 @@
|
|||||||
require "hbc/artifact/base"
|
require "hbc/artifact/abstract_artifact"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class NestedContainer < Base
|
class NestedContainer < AbstractArtifact
|
||||||
def install_phase
|
attr_reader :path
|
||||||
@cask.artifacts[:nested_container].each { |container| extract(container) }
|
|
||||||
|
def initialize(cask, path)
|
||||||
|
super(cask)
|
||||||
|
@path = cask.staged_path.join(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract(container_relative_path)
|
def install_phase(**options)
|
||||||
source = @cask.staged_path.join(container_relative_path)
|
extract(**options)
|
||||||
container = Container.for_path(source, @command)
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def extract(command: nil, verbose: nil, **_)
|
||||||
|
container = Container.for_path(path, command)
|
||||||
|
|
||||||
unless container
|
unless container
|
||||||
raise CaskError, "Aw dang, could not identify nested container at '#{source}'"
|
raise CaskError, "Aw dang, could not identify nested container at '#{source}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
ohai "Extracting nested container #{source.basename}"
|
ohai "Extracting nested container #{path.relative_path_from(cask.staged_path)}"
|
||||||
container.new(@cask, source, @command, verbose: verbose?).extract
|
container.new(cask, path, command, verbose: verbose).extract
|
||||||
FileUtils.remove_entry_secure(source)
|
FileUtils.remove_entry_secure(path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
require "hbc/artifact/base"
|
require "hbc/artifact/abstract_artifact"
|
||||||
|
|
||||||
require "hbc/utils/hash_validator"
|
require "hbc/utils/hash_validator"
|
||||||
|
|
||||||
@ -6,62 +6,57 @@ require "vendor/plist/plist"
|
|||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Pkg < Base
|
class Pkg < AbstractArtifact
|
||||||
attr_reader :pkg_relative_path
|
attr_reader :pkg_relative_path
|
||||||
|
|
||||||
def self.artifact_dsl_key
|
def self.from_args(cask, path, **options)
|
||||||
:pkg
|
options.extend(HashValidator).assert_valid_keys(:allow_untrusted, :choices)
|
||||||
|
new(cask, path, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_pkg_description(pkg_description)
|
attr_reader :path, :options
|
||||||
@pkg_relative_path = pkg_description.shift
|
|
||||||
@pkg_install_opts = pkg_description.shift
|
def initialize(cask, path, **options)
|
||||||
begin
|
super(cask)
|
||||||
if @pkg_install_opts.respond_to?(:keys)
|
@path = cask.staged_path.join(path)
|
||||||
@pkg_install_opts.extend(HashValidator).assert_valid_keys(:allow_untrusted, :choices)
|
@options = options
|
||||||
elsif @pkg_install_opts
|
|
||||||
raise
|
|
||||||
end
|
|
||||||
raise if pkg_description.nil?
|
|
||||||
rescue StandardError
|
|
||||||
raise CaskInvalidError.new(@cask, "Bad pkg stanza")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def pkg_install_opts(opt)
|
def summarize
|
||||||
@pkg_install_opts[opt] if @pkg_install_opts.respond_to?(:keys)
|
path.relative_path_from(cask.staged_path).to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_phase
|
def install_phase(**options)
|
||||||
@cask.artifacts[:pkg].each { |pkg_description| run_installer(pkg_description) }
|
run_installer(**options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_installer(pkg_description)
|
private
|
||||||
load_pkg_description pkg_description
|
|
||||||
ohai "Running installer for #{@cask}; your password may be necessary."
|
def run_installer(command: nil, verbose: false, **options)
|
||||||
|
ohai "Running installer for #{cask}; your password may be necessary."
|
||||||
ohai "Package installers may write to any location; options such as --appdir are ignored."
|
ohai "Package installers may write to any location; options such as --appdir are ignored."
|
||||||
source = @cask.staged_path.join(pkg_relative_path)
|
unless path.exist?
|
||||||
unless source.exist?
|
raise CaskError, "pkg source file not found: '#{path.relative_path_from(cask.staged_path)}'"
|
||||||
raise CaskError, "pkg source file not found: '#{source}'"
|
|
||||||
end
|
end
|
||||||
args = [
|
args = [
|
||||||
"-pkg", source,
|
"-pkg", path,
|
||||||
"-target", "/"
|
"-target", "/"
|
||||||
]
|
]
|
||||||
args << "-verboseR" if verbose?
|
args << "-verboseR" if verbose
|
||||||
args << "-allowUntrusted" if pkg_install_opts :allow_untrusted
|
args << "-allowUntrusted" if options.fetch(:allow_untrusted, false)
|
||||||
with_choices_file do |choices_path|
|
with_choices_file do |choices_path|
|
||||||
args << "-applyChoiceChangesXML" << choices_path if choices_path
|
args << "-applyChoiceChangesXML" << choices_path if choices_path
|
||||||
@command.run!("/usr/sbin/installer", sudo: true, args: args, print_stdout: true)
|
command.run!("/usr/sbin/installer", sudo: true, args: args, print_stdout: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_choices_file
|
def with_choices_file
|
||||||
return yield nil unless pkg_install_opts(:choices)
|
choices = options.fetch(:choices, {})
|
||||||
|
return yield nil if choices.empty?
|
||||||
|
|
||||||
Tempfile.open(["choices", ".xml"]) do |file|
|
Tempfile.open(["choices", ".xml"]) do |file|
|
||||||
begin
|
begin
|
||||||
file.write Plist::Emit.dump(pkg_install_opts(:choices))
|
file.write Plist::Emit.dump(choices)
|
||||||
file.close
|
file.close
|
||||||
yield file.path
|
yield file.path
|
||||||
ensure
|
ensure
|
||||||
|
@ -3,7 +3,7 @@ require "hbc/artifact/moved"
|
|||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Prefpane < Moved
|
class Prefpane < Moved
|
||||||
def self.artifact_english_name
|
def self.english_name
|
||||||
"Preference Pane"
|
"Preference Pane"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,22 +3,24 @@ require "hbc/artifact/moved"
|
|||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Qlplugin < Moved
|
class Qlplugin < Moved
|
||||||
def self.artifact_english_name
|
def self.english_name
|
||||||
"QuickLook Plugin"
|
"QuickLook Plugin"
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_phase
|
def install_phase(**options)
|
||||||
super
|
super(**options)
|
||||||
reload_quicklook
|
reload_quicklook(**options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_phase
|
def uninstall_phase(**options)
|
||||||
super
|
super(**options)
|
||||||
reload_quicklook
|
reload_quicklook(**options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reload_quicklook
|
private
|
||||||
@command.run!("/usr/bin/qlmanage", args: ["-r"])
|
|
||||||
|
def reload_quicklook(command: nil, **_)
|
||||||
|
command.run!("/usr/bin/qlmanage", args: ["-r"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,33 +1,57 @@
|
|||||||
require "hbc/artifact/base"
|
require "hbc/artifact/abstract_artifact"
|
||||||
|
|
||||||
require "hbc/utils/hash_validator"
|
require "hbc/utils/hash_validator"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Relocated < Base
|
class Relocated < AbstractArtifact
|
||||||
def summary
|
def self.from_args(cask, *args)
|
||||||
{
|
source_string, target_hash = args
|
||||||
english_description: self.class.english_description,
|
|
||||||
contents: @cask.artifacts[self.class.artifact_dsl_key].map(&method(:summarize_artifact)).compact,
|
if target_hash
|
||||||
}
|
raise CaskInvalidError unless target_hash.respond_to?(:keys)
|
||||||
|
target_hash.extend(HashValidator).assert_valid_keys(:target)
|
||||||
|
end
|
||||||
|
|
||||||
|
target_hash ||= {}
|
||||||
|
|
||||||
|
new(cask, source_string, **target_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.resolve_target(target)
|
||||||
|
Hbc.public_send(dirmethod).join(target)
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :source, :target
|
attr_reader :source, :target
|
||||||
|
|
||||||
def printable_target
|
def initialize(cask, source, target: nil)
|
||||||
target.to_s.sub(/^#{ENV['HOME']}(#{File::SEPARATOR}|$)/, "~/")
|
super(cask)
|
||||||
|
|
||||||
|
@source_string = source.to_s
|
||||||
|
@target_string = target.to_s
|
||||||
|
source = cask.staged_path.join(source)
|
||||||
|
@source = source
|
||||||
|
target ||= source.basename
|
||||||
|
@target = self.class.resolve_target(target)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def summarize
|
||||||
|
target_string = @target_string.empty? ? "" : " -> #{@target_string}"
|
||||||
|
"#{@source_string}#{target_string}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
ALT_NAME_ATTRIBUTE = "com.apple.metadata:kMDItemAlternateNames".freeze
|
ALT_NAME_ATTRIBUTE = "com.apple.metadata:kMDItemAlternateNames".freeze
|
||||||
|
|
||||||
# Try to make the asset searchable under the target name. Spotlight
|
# Try to make the asset searchable under the target name. Spotlight
|
||||||
# respects this attribute for many filetypes, but ignores it for App
|
# respects this attribute for many filetypes, but ignores it for App
|
||||||
# bundles. Alfred 2.2 respects it even for App bundles.
|
# bundles. Alfred 2.2 respects it even for App bundles.
|
||||||
def add_altname_metadata(file, altname)
|
def add_altname_metadata(file, altname, command: nil)
|
||||||
return if altname.casecmp(file.basename).zero?
|
return if altname.to_s.casecmp(file.basename.to_s).zero?
|
||||||
odebug "Adding #{ALT_NAME_ATTRIBUTE} metadata"
|
odebug "Adding #{ALT_NAME_ATTRIBUTE} metadata"
|
||||||
altnames = @command.run("/usr/bin/xattr",
|
altnames = command.run("/usr/bin/xattr",
|
||||||
args: ["-p", ALT_NAME_ATTRIBUTE, file.to_s],
|
args: ["-p", ALT_NAME_ATTRIBUTE, file],
|
||||||
print_stderr: false).stdout.sub(/\A\((.*)\)\Z/, '\1')
|
print_stderr: false).stdout.sub(/\A\((.*)\)\Z/, '\1')
|
||||||
odebug "Existing metadata is: '#{altnames}'"
|
odebug "Existing metadata is: '#{altnames}'"
|
||||||
altnames.concat(", ") unless altnames.empty?
|
altnames.concat(", ") unless altnames.empty?
|
||||||
@ -35,31 +59,15 @@ module Hbc
|
|||||||
altnames = "(#{altnames})"
|
altnames = "(#{altnames})"
|
||||||
|
|
||||||
# Some packages are shipped as u=rx (e.g. Bitcoin Core)
|
# Some packages are shipped as u=rx (e.g. Bitcoin Core)
|
||||||
@command.run!("/bin/chmod", args: ["--", "u+rw", file, file.realpath])
|
command.run!("/bin/chmod", args: ["--", "u+rw", file, file.realpath])
|
||||||
|
|
||||||
@command.run!("/usr/bin/xattr",
|
command.run!("/usr/bin/xattr",
|
||||||
args: ["-w", ALT_NAME_ATTRIBUTE, altnames, file],
|
args: ["-w", ALT_NAME_ATTRIBUTE, altnames, file],
|
||||||
print_stderr: false)
|
print_stderr: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def each_artifact
|
def printable_target
|
||||||
@cask.artifacts[self.class.artifact_dsl_key].each do |artifact|
|
target.to_s.sub(/^#{ENV['HOME']}(#{File::SEPARATOR}|$)/, "~/")
|
||||||
load_specification(artifact)
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_specification(artifact_spec)
|
|
||||||
source_string, target_hash = artifact_spec
|
|
||||||
raise CaskInvalidError if source_string.nil?
|
|
||||||
@source = @cask.staged_path.join(source_string)
|
|
||||||
if target_hash
|
|
||||||
raise CaskInvalidError unless target_hash.respond_to?(:keys)
|
|
||||||
target_hash.extend(HashValidator).assert_valid_keys(:target)
|
|
||||||
@target = Hbc.send(self.class.artifact_dirmethod).join(target_hash[:target])
|
|
||||||
else
|
|
||||||
@target = Hbc.send(self.class.artifact_dirmethod).join(source.basename)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
require "hbc/artifact/base"
|
require "hbc/artifact/abstract_artifact"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class StageOnly < Base
|
class StageOnly < AbstractArtifact
|
||||||
def self.artifact_dsl_key
|
def self.from_args(cask, *args)
|
||||||
:stage_only
|
if args != [true]
|
||||||
|
raise CaskInvalidError.new(cask.token, "'stage_only' takes only a single argument: true")
|
||||||
|
end
|
||||||
|
|
||||||
|
new(cask)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(cask)
|
||||||
|
super(cask)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,11 +3,11 @@ require "hbc/artifact/moved"
|
|||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Suite < Moved
|
class Suite < Moved
|
||||||
def self.artifact_english_name
|
def self.english_name
|
||||||
"App Suite"
|
"App Suite"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.artifact_dirmethod
|
def self.dirmethod
|
||||||
:appdir
|
:appdir
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -8,47 +8,18 @@ module Hbc
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.english_description
|
def self.english_description
|
||||||
"#{artifact_english_name} #{link_type_english_name}s"
|
"#{english_name} #{link_type_english_name}s"
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_phase
|
def install_phase(**options)
|
||||||
each_artifact(&method(:link))
|
link(**options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def uninstall_phase
|
def uninstall_phase(**options)
|
||||||
each_artifact(&method(:unlink))
|
unlink(**options)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def summarize_installed
|
||||||
|
|
||||||
def link
|
|
||||||
unless source.exist?
|
|
||||||
raise CaskError, "It seems the #{self.class.link_type_english_name.downcase} source '#{source}' is not there."
|
|
||||||
end
|
|
||||||
|
|
||||||
if target.exist? && !target.symlink?
|
|
||||||
raise CaskError, "It seems there is already #{self.class.artifact_english_article} #{self.class.artifact_english_name} at '#{target}'; not linking."
|
|
||||||
end
|
|
||||||
|
|
||||||
ohai "Linking #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'."
|
|
||||||
create_filesystem_link(source, target)
|
|
||||||
end
|
|
||||||
|
|
||||||
def unlink
|
|
||||||
return unless target.symlink?
|
|
||||||
ohai "Unlinking #{self.class.artifact_english_name} '#{target}'."
|
|
||||||
target.delete
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_filesystem_link(source, target)
|
|
||||||
target.dirname.mkpath
|
|
||||||
@command.run!("/bin/ln", args: ["-h", "-f", "-s", "--", source, target])
|
|
||||||
add_altname_metadata source, target.basename.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def summarize_artifact(artifact_spec)
|
|
||||||
load_specification artifact_spec
|
|
||||||
|
|
||||||
if target.symlink? && target.exist? && target.readlink.exist?
|
if target.symlink? && target.exist? && target.readlink.exist?
|
||||||
"#{printable_target} -> #{target.readlink} (#{target.readlink.abv})"
|
"#{printable_target} -> #{target.readlink} (#{target.readlink.abv})"
|
||||||
else
|
else
|
||||||
@ -61,6 +32,33 @@ module Hbc
|
|||||||
Formatter.error(string, label: "Broken Link")
|
Formatter.error(string, label: "Broken Link")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def link(**options)
|
||||||
|
unless source.exist?
|
||||||
|
raise CaskError, "It seems the #{self.class.link_type_english_name.downcase} source '#{source}' is not there."
|
||||||
|
end
|
||||||
|
|
||||||
|
if target.exist? && !target.symlink?
|
||||||
|
raise CaskError, "It seems there is already #{self.class.english_article} #{self.class.english_name} at '#{target}'; not linking."
|
||||||
|
end
|
||||||
|
|
||||||
|
ohai "Linking #{self.class.english_name} '#{source.basename}' to '#{target}'."
|
||||||
|
create_filesystem_link(**options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unlink(**)
|
||||||
|
return unless target.symlink?
|
||||||
|
ohai "Unlinking #{self.class.english_name} '#{target}'."
|
||||||
|
target.delete
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_filesystem_link(command: nil, **_)
|
||||||
|
target.dirname.mkpath
|
||||||
|
command.run!("/bin/ln", args: ["-h", "-f", "-s", "--", source, target])
|
||||||
|
add_altname_metadata(source, target.basename, command: command)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
require "hbc/artifact/uninstall_base"
|
require "hbc/artifact/abstract_uninstall"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Uninstall < UninstallBase
|
class Uninstall < AbstractUninstall
|
||||||
def uninstall_phase
|
def uninstall_phase(**options)
|
||||||
dispatch_uninstall_directives
|
dispatch_uninstall_directives(**options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
require "hbc/artifact/uninstall_base"
|
require "hbc/artifact/abstract_uninstall"
|
||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
module Artifact
|
module Artifact
|
||||||
class Zap < UninstallBase
|
class Zap < AbstractUninstall
|
||||||
def zap_phase
|
def zap_phase(**options)
|
||||||
dispatch_uninstall_directives
|
dispatch_uninstall_directives(**options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -214,12 +214,10 @@ module Hbc
|
|||||||
end
|
end
|
||||||
|
|
||||||
def check_generic_artifacts
|
def check_generic_artifacts
|
||||||
cask.artifacts[:artifact].each do |source, target_hash|
|
cask.artifacts[:artifact].each do |artifact|
|
||||||
unless target_hash.is_a?(Hash) && target_hash[:target]
|
unless artifact.target.absolute?
|
||||||
add_error "target required for generic artifact #{source}"
|
add_error "target must be absolute path for #{artifact.class.english_name} #{artifact.source}"
|
||||||
next
|
|
||||||
end
|
end
|
||||||
add_error "target must be absolute path for generic artifact #{source}" unless Pathname.new(target_hash[:target]).absolute?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ module Hbc
|
|||||||
@token = token
|
@token = token
|
||||||
@sourcefile_path = sourcefile_path
|
@sourcefile_path = sourcefile_path
|
||||||
@tap = tap
|
@tap = tap
|
||||||
@dsl = DSL.new(@token)
|
@dsl = DSL.new(self)
|
||||||
return unless block_given?
|
return unless block_given?
|
||||||
@dsl.instance_eval(&block)
|
@dsl.instance_eval(&block)
|
||||||
@dsl.language_eval
|
@dsl.language_eval
|
||||||
|
@ -69,12 +69,10 @@ module Hbc
|
|||||||
|
|
||||||
def self.artifact_info(cask)
|
def self.artifact_info(cask)
|
||||||
ohai "Artifacts"
|
ohai "Artifacts"
|
||||||
DSL::ORDINARY_ARTIFACT_TYPES.each do |type|
|
DSL::ORDINARY_ARTIFACT_CLASSES.flat_map { |klass| klass.for_cask(cask) }
|
||||||
next if cask.artifacts[type].empty?
|
.select { |artifact| artifact.respond_to?(:install_phase) }
|
||||||
cask.artifacts[type].each do |artifact|
|
.each do |artifact|
|
||||||
activatable_item = (type == :stage_only) ? "<none>" : artifact.first
|
puts artifact.to_s
|
||||||
puts "#{activatable_item} (#{type})"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -21,34 +21,9 @@ module Hbc
|
|||||||
# brew cask _stanza artifacts --table --yaml alfred google-chrome adium voicemac logisim vagrant
|
# brew cask _stanza artifacts --table --yaml alfred google-chrome adium voicemac logisim vagrant
|
||||||
#
|
#
|
||||||
|
|
||||||
# TODO: this should be retrievable from Hbc::DSL
|
ARTIFACTS =
|
||||||
ARTIFACTS = Set.new [
|
DSL::ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key) +
|
||||||
:app,
|
DSL::ARTIFACT_BLOCK_CLASSES.map(&:dsl_key)
|
||||||
:suite,
|
|
||||||
:artifact,
|
|
||||||
:prefpane,
|
|
||||||
:qlplugin,
|
|
||||||
:dictionary,
|
|
||||||
:font,
|
|
||||||
:service,
|
|
||||||
:colorpicker,
|
|
||||||
:binary,
|
|
||||||
:input_method,
|
|
||||||
:internet_plugin,
|
|
||||||
:audio_unit_plugin,
|
|
||||||
:vst_plugin,
|
|
||||||
:vst3_plugin,
|
|
||||||
:screen_saver,
|
|
||||||
:pkg,
|
|
||||||
:installer,
|
|
||||||
:stage_only,
|
|
||||||
:nested_container,
|
|
||||||
:uninstall,
|
|
||||||
:preflight,
|
|
||||||
:postflight,
|
|
||||||
:uninstall_preflight,
|
|
||||||
:uninstall_postflight,
|
|
||||||
]
|
|
||||||
|
|
||||||
option "--table", :table, false
|
option "--table", :table, false
|
||||||
option "--quiet", :quiet, false
|
option "--quiet", :quiet, false
|
||||||
@ -93,7 +68,7 @@ module Hbc
|
|||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
value = cask.send(@stanza)
|
value = cask.send(stanza)
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
opoo "failure calling '#{stanza}' on Cask '#{cask}'" unless quiet?
|
opoo "failure calling '#{stanza}' on Cask '#{cask}'" unless quiet?
|
||||||
puts ""
|
puts ""
|
||||||
@ -108,8 +83,8 @@ module Hbc
|
|||||||
|
|
||||||
value = value.fetch(artifact_name).to_a.flatten if artifact_name
|
value = value.fetch(artifact_name).to_a.flatten if artifact_name
|
||||||
|
|
||||||
if @format
|
if format
|
||||||
puts value.send(@format)
|
puts value.send(format)
|
||||||
elsif artifact_name || value.is_a?(Symbol)
|
elsif artifact_name || value.is_a?(Symbol)
|
||||||
puts value.inspect
|
puts value.inspect
|
||||||
else
|
else
|
||||||
|
@ -30,9 +30,9 @@ module Hbc
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.list_artifacts(cask)
|
def self.list_artifacts(cask)
|
||||||
Artifact.for_cask(cask).each do |artifact|
|
Artifact.for_cask(cask).group_by(&:class).each do |klass, artifacts|
|
||||||
summary = artifact.summary
|
next unless klass.respond_to?(:english_description)
|
||||||
ohai summary[:english_description], summary[:contents] unless summary.empty?
|
ohai klass.english_description, artifacts.map(&:summarize_installed)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
require "set"
|
require "set"
|
||||||
require "locale"
|
require "locale"
|
||||||
|
|
||||||
|
require "hbc/artifact"
|
||||||
|
|
||||||
require "hbc/dsl/appcast"
|
require "hbc/dsl/appcast"
|
||||||
require "hbc/dsl/base"
|
require "hbc/dsl/base"
|
||||||
require "hbc/dsl/caveats"
|
require "hbc/dsl/caveats"
|
||||||
@ -8,7 +10,6 @@ require "hbc/dsl/conflicts_with"
|
|||||||
require "hbc/dsl/container"
|
require "hbc/dsl/container"
|
||||||
require "hbc/dsl/depends_on"
|
require "hbc/dsl/depends_on"
|
||||||
require "hbc/dsl/gpg"
|
require "hbc/dsl/gpg"
|
||||||
require "hbc/dsl/installer"
|
|
||||||
require "hbc/dsl/postflight"
|
require "hbc/dsl/postflight"
|
||||||
require "hbc/dsl/preflight"
|
require "hbc/dsl/preflight"
|
||||||
require "hbc/dsl/stanza_proxy"
|
require "hbc/dsl/stanza_proxy"
|
||||||
@ -18,39 +19,35 @@ require "hbc/dsl/version"
|
|||||||
|
|
||||||
module Hbc
|
module Hbc
|
||||||
class DSL
|
class DSL
|
||||||
ORDINARY_ARTIFACT_TYPES = [
|
ORDINARY_ARTIFACT_CLASSES = [
|
||||||
:app,
|
Artifact::Installer,
|
||||||
:artifact,
|
Artifact::App,
|
||||||
:audio_unit_plugin,
|
Artifact::Artifact,
|
||||||
:binary,
|
Artifact::AudioUnitPlugin,
|
||||||
:colorpicker,
|
Artifact::Binary,
|
||||||
:dictionary,
|
Artifact::Colorpicker,
|
||||||
:font,
|
Artifact::Dictionary,
|
||||||
:input_method,
|
Artifact::Font,
|
||||||
:internet_plugin,
|
Artifact::InputMethod,
|
||||||
:pkg,
|
Artifact::InternetPlugin,
|
||||||
:prefpane,
|
Artifact::Pkg,
|
||||||
:qlplugin,
|
Artifact::Prefpane,
|
||||||
:screen_saver,
|
Artifact::Qlplugin,
|
||||||
:service,
|
Artifact::ScreenSaver,
|
||||||
:stage_only,
|
Artifact::Service,
|
||||||
:suite,
|
Artifact::StageOnly,
|
||||||
:vst_plugin,
|
Artifact::Suite,
|
||||||
:vst3_plugin,
|
Artifact::VstPlugin,
|
||||||
|
Artifact::Vst3Plugin,
|
||||||
|
Artifact::Uninstall,
|
||||||
|
Artifact::Zap,
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
ACTIVATABLE_ARTIFACT_TYPES = ([:installer, *ORDINARY_ARTIFACT_TYPES] - [:stage_only]).freeze
|
ACTIVATABLE_ARTIFACT_TYPES = (ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key) - [:stage_only]).freeze
|
||||||
|
|
||||||
SPECIAL_ARTIFACT_TYPES = [
|
ARTIFACT_BLOCK_CLASSES = [
|
||||||
:uninstall,
|
Artifact::PreflightBlock,
|
||||||
:zap,
|
Artifact::PostflightBlock,
|
||||||
].freeze
|
|
||||||
|
|
||||||
ARTIFACT_BLOCK_TYPES = [
|
|
||||||
:preflight,
|
|
||||||
:postflight,
|
|
||||||
:uninstall_preflight,
|
|
||||||
:uninstall_postflight,
|
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
DSL_METHODS = Set.new [
|
DSL_METHODS = Set.new [
|
||||||
@ -72,15 +69,15 @@ module Hbc
|
|||||||
:url,
|
:url,
|
||||||
:version,
|
:version,
|
||||||
:appdir,
|
:appdir,
|
||||||
*ORDINARY_ARTIFACT_TYPES,
|
*ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
|
||||||
*ACTIVATABLE_ARTIFACT_TYPES,
|
*ACTIVATABLE_ARTIFACT_TYPES,
|
||||||
*SPECIAL_ARTIFACT_TYPES,
|
*ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },
|
||||||
*ARTIFACT_BLOCK_TYPES,
|
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
attr_reader :token
|
attr_reader :token, :cask
|
||||||
def initialize(token)
|
def initialize(cask)
|
||||||
@token = token
|
@cask = cask
|
||||||
|
@token = cask.token
|
||||||
end
|
end
|
||||||
|
|
||||||
def name(*args)
|
def name(*args)
|
||||||
@ -93,12 +90,14 @@ module Hbc
|
|||||||
return instance_variable_get("@#{stanza}") if should_return
|
return instance_variable_get("@#{stanza}") if should_return
|
||||||
|
|
||||||
if instance_variable_defined?("@#{stanza}")
|
if instance_variable_defined?("@#{stanza}")
|
||||||
raise CaskInvalidError.new(token, "'#{stanza}' stanza may only appear once")
|
raise CaskInvalidError.new(cask, "'#{stanza}' stanza may only appear once.")
|
||||||
end
|
end
|
||||||
|
|
||||||
instance_variable_set("@#{stanza}", yield)
|
instance_variable_set("@#{stanza}", yield)
|
||||||
|
rescue CaskInvalidError
|
||||||
|
raise
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
raise CaskInvalidError.new(token, "'#{stanza}' stanza failed with: #{e}")
|
raise CaskInvalidError.new(cask, "'#{stanza}' stanza failed with: #{e}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def homepage(homepage = nil)
|
def homepage(homepage = nil)
|
||||||
@ -113,7 +112,7 @@ module Hbc
|
|||||||
return unless default
|
return unless default
|
||||||
|
|
||||||
unless @language_blocks.default.nil?
|
unless @language_blocks.default.nil?
|
||||||
raise CaskInvalidError.new(token, "Only one default language may be defined")
|
raise CaskInvalidError.new(cask, "Only one default language may be defined.")
|
||||||
end
|
end
|
||||||
|
|
||||||
@language_blocks.default = block
|
@language_blocks.default = block
|
||||||
@ -163,7 +162,7 @@ module Hbc
|
|||||||
DSL::Container.new(*args).tap do |container|
|
DSL::Container.new(*args).tap do |container|
|
||||||
# TODO: remove this backward-compatibility section after removing nested_container
|
# TODO: remove this backward-compatibility section after removing nested_container
|
||||||
if container && container.nested
|
if container && container.nested
|
||||||
artifacts[:nested_container] << container.nested
|
artifacts[:nested_container] << Artifact::NestedContainer.new(cask, container.nested)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -173,7 +172,7 @@ module Hbc
|
|||||||
def version(arg = nil)
|
def version(arg = nil)
|
||||||
set_unique_stanza(:version, arg.nil?) do
|
set_unique_stanza(:version, arg.nil?) do
|
||||||
if !arg.is_a?(String) && arg != :latest
|
if !arg.is_a?(String) && arg != :latest
|
||||||
raise CaskInvalidError.new(token, "invalid 'version' value: '#{arg.inspect}'")
|
raise CaskInvalidError.new(cask, "invalid 'version' value: '#{arg.inspect}'")
|
||||||
end
|
end
|
||||||
DSL::Version.new(arg)
|
DSL::Version.new(arg)
|
||||||
end
|
end
|
||||||
@ -182,7 +181,7 @@ module Hbc
|
|||||||
def sha256(arg = nil)
|
def sha256(arg = nil)
|
||||||
set_unique_stanza(:sha256, arg.nil?) do
|
set_unique_stanza(:sha256, arg.nil?) do
|
||||||
if !arg.is_a?(String) && arg != :no_check
|
if !arg.is_a?(String) && arg != :no_check
|
||||||
raise CaskInvalidError.new(token, "invalid 'sha256' value: '#{arg.inspect}'")
|
raise CaskInvalidError.new(cask, "invalid 'sha256' value: '#{arg.inspect}'")
|
||||||
end
|
end
|
||||||
arg
|
arg
|
||||||
end
|
end
|
||||||
@ -195,7 +194,7 @@ module Hbc
|
|||||||
begin
|
begin
|
||||||
@depends_on.load(*args)
|
@depends_on.load(*args)
|
||||||
rescue RuntimeError => e
|
rescue RuntimeError => e
|
||||||
raise CaskInvalidError.new(token, e)
|
raise CaskInvalidError.new(cask, e)
|
||||||
end
|
end
|
||||||
@depends_on
|
@depends_on
|
||||||
end
|
end
|
||||||
@ -237,39 +236,29 @@ module Hbc
|
|||||||
set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }
|
set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }
|
||||||
end
|
end
|
||||||
|
|
||||||
ORDINARY_ARTIFACT_TYPES.each do |type|
|
ORDINARY_ARTIFACT_CLASSES.each do |klass|
|
||||||
|
type = klass.dsl_key
|
||||||
|
|
||||||
define_method(type) do |*args|
|
define_method(type) do |*args|
|
||||||
if type == :stage_only
|
begin
|
||||||
if args != [true]
|
if [*artifacts.keys, type].include?(:stage_only) && (artifacts.keys & ACTIVATABLE_ARTIFACT_TYPES).any?
|
||||||
raise CaskInvalidError.new(token, "'stage_only' takes a single argument: true")
|
raise CaskInvalidError.new(cask, "'stage_only' must be the only activatable artifact.")
|
||||||
end
|
end
|
||||||
|
|
||||||
unless (artifacts.keys & ACTIVATABLE_ARTIFACT_TYPES).empty?
|
artifacts[type].add(klass.from_args(cask, *args))
|
||||||
raise CaskInvalidError.new(token, "'stage_only' must be the only activatable artifact")
|
rescue CaskInvalidError
|
||||||
end
|
raise
|
||||||
end
|
|
||||||
|
|
||||||
artifacts[type].add(args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def installer(*args)
|
|
||||||
return artifacts[:installer] if args.empty?
|
|
||||||
artifacts[:installer] << DSL::Installer.new(*args)
|
|
||||||
raise "'stage_only' must be the only activatable artifact" if artifacts.key?(:stage_only)
|
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
raise CaskInvalidError.new(token, e)
|
raise CaskInvalidError.new(cask, "invalid '#{klass.dsl_key}' stanza: #{e}")
|
||||||
end
|
end
|
||||||
|
|
||||||
SPECIAL_ARTIFACT_TYPES.each do |type|
|
|
||||||
define_method(type) do |*args|
|
|
||||||
artifacts[type].merge(args)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ARTIFACT_BLOCK_TYPES.each do |type|
|
ARTIFACT_BLOCK_CLASSES.each do |klass|
|
||||||
define_method(type) do |&block|
|
[klass.dsl_key, klass.uninstall_dsl_key].each do |dsl_key|
|
||||||
artifacts[type] << block
|
define_method(dsl_key) do |&block|
|
||||||
|
artifacts[dsl_key] << block
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
module Hbc
|
|
||||||
class DSL
|
|
||||||
class Installer
|
|
||||||
VALID_KEYS = Set.new [
|
|
||||||
:manual,
|
|
||||||
:script,
|
|
||||||
]
|
|
||||||
|
|
||||||
attr_accessor(*VALID_KEYS)
|
|
||||||
|
|
||||||
def initialize(*parameters)
|
|
||||||
raise CaskInvalidError.new(token, "'installer' stanza requires an argument") if parameters.empty?
|
|
||||||
parameters = {}.merge(*parameters)
|
|
||||||
if parameters.key?(:script) && !parameters[:script].respond_to?(:key?)
|
|
||||||
if parameters.key?(:executable)
|
|
||||||
raise CaskInvalidError.new(token, "'installer' stanza gave arguments for both :script and :executable")
|
|
||||||
end
|
|
||||||
parameters[:executable] = parameters[:script]
|
|
||||||
parameters.delete(:script)
|
|
||||||
parameters = { script: parameters }
|
|
||||||
end
|
|
||||||
unless parameters.keys.length == 1
|
|
||||||
raise "invalid 'installer' stanza: only one of #{VALID_KEYS.inspect} is permitted"
|
|
||||||
end
|
|
||||||
key = parameters.keys.first
|
|
||||||
raise "invalid 'installer' stanza key: '#{key.inspect}'" unless VALID_KEYS.include?(key)
|
|
||||||
writer_method = "#{key}=".to_sym
|
|
||||||
send(writer_method, parameters[key])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -177,7 +177,7 @@ module Hbc
|
|||||||
already_installed_artifacts = []
|
already_installed_artifacts = []
|
||||||
|
|
||||||
odebug "Installing artifacts"
|
odebug "Installing artifacts"
|
||||||
artifacts = Artifact.for_cask(@cask, command: @command, verbose: verbose?, force: force?)
|
artifacts = Artifact.for_cask(@cask)
|
||||||
odebug "#{artifacts.length} artifact/s defined", artifacts
|
odebug "#{artifacts.length} artifact/s defined", artifacts
|
||||||
|
|
||||||
artifacts.each do |artifact|
|
artifacts.each do |artifact|
|
||||||
@ -188,7 +188,7 @@ module Hbc
|
|||||||
next unless binaries?
|
next unless binaries?
|
||||||
end
|
end
|
||||||
|
|
||||||
artifact.install_phase
|
artifact.install_phase(command: @command, verbose: verbose?, force: force?)
|
||||||
already_installed_artifacts.unshift(artifact)
|
already_installed_artifacts.unshift(artifact)
|
||||||
end
|
end
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
@ -196,7 +196,7 @@ module Hbc
|
|||||||
already_installed_artifacts.each do |artifact|
|
already_installed_artifacts.each do |artifact|
|
||||||
next unless artifact.respond_to?(:uninstall_phase)
|
next unless artifact.respond_to?(:uninstall_phase)
|
||||||
odebug "Reverting installation of artifact of class #{artifact.class}"
|
odebug "Reverting installation of artifact of class #{artifact.class}"
|
||||||
artifact.uninstall_phase
|
artifact.uninstall_phase(command: @command, verbose: verbose?, force: force?)
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
purge_versioned_files
|
purge_versioned_files
|
||||||
@ -374,25 +374,27 @@ module Hbc
|
|||||||
|
|
||||||
def uninstall_artifacts
|
def uninstall_artifacts
|
||||||
odebug "Un-installing artifacts"
|
odebug "Un-installing artifacts"
|
||||||
artifacts = Artifact.for_cask(@cask, command: @command, verbose: verbose?, force: force?)
|
artifacts = Artifact.for_cask(@cask)
|
||||||
|
|
||||||
odebug "#{artifacts.length} artifact/s defined", artifacts
|
odebug "#{artifacts.length} artifact/s defined", artifacts
|
||||||
|
|
||||||
artifacts.each do |artifact|
|
artifacts.each do |artifact|
|
||||||
next unless artifact.respond_to?(:uninstall_phase)
|
next unless artifact.respond_to?(:uninstall_phase)
|
||||||
odebug "Un-installing artifact of class #{artifact.class}"
|
odebug "Un-installing artifact of class #{artifact.class}"
|
||||||
artifact.uninstall_phase
|
artifact.uninstall_phase(command: @command, verbose: verbose?, force: force?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def zap
|
def zap
|
||||||
ohai %Q(Implied "brew cask uninstall #{@cask}")
|
ohai %Q(Implied "brew cask uninstall #{@cask}")
|
||||||
uninstall_artifacts
|
uninstall_artifacts
|
||||||
if Artifact::Zap.me?(@cask)
|
if (zap_stanzas = Artifact::Zap.for_cask(@cask)).empty?
|
||||||
ohai "Dispatching zap stanza"
|
|
||||||
Artifact::Zap.new(@cask, command: @command).zap_phase
|
|
||||||
else
|
|
||||||
opoo "No zap stanza present for Cask '#{@cask}'"
|
opoo "No zap stanza present for Cask '#{@cask}'"
|
||||||
|
else
|
||||||
|
ohai "Dispatching zap stanza"
|
||||||
|
zap_stanzas.each do |stanza|
|
||||||
|
stanza.zap_phase(command: @command, verbose: verbose?, force: force?)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
ohai "Removing all staged versions of Cask '#{@cask}'"
|
ohai "Removing all staged versions of Cask '#{@cask}'"
|
||||||
purge_caskroom_path
|
purge_caskroom_path
|
||||||
|
@ -4,7 +4,7 @@ module Hbc
|
|||||||
index = 0 if index == :first
|
index = 0 if index == :first
|
||||||
index = 1 if index == :second
|
index = 1 if index == :second
|
||||||
index = -1 if index == :last
|
index = -1 if index == :last
|
||||||
Hbc.appdir.join(@cask.artifacts[:app].to_a.at(index).first, "Contents", "Info.plist")
|
@cask.artifacts[:app].to_a.at(index).target.join("Contents", "Info.plist")
|
||||||
end
|
end
|
||||||
|
|
||||||
def plist_exec(cmd)
|
def plist_exec(cmd)
|
||||||
|
@ -3,7 +3,7 @@ describe Hbc::Artifact::App, :cask do
|
|||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-alt-target.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-alt-target.rb") }
|
||||||
|
|
||||||
let(:install_phase) {
|
let(:install_phase) {
|
||||||
-> { Hbc::Artifact::App.new(cask).install_phase }
|
-> { described_class.for_cask(cask).each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
let(:source_path) { cask.staged_path.join("Caffeine.app") }
|
let(:source_path) { cask.staged_path.join("Caffeine.app") }
|
||||||
|
@ -2,13 +2,13 @@ describe Hbc::Artifact::App, :cask do
|
|||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-caffeine.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-caffeine.rb") }
|
||||||
let(:command) { Hbc::SystemCommand }
|
let(:command) { Hbc::SystemCommand }
|
||||||
let(:force) { false }
|
let(:force) { false }
|
||||||
let(:app) { Hbc::Artifact::App.new(cask, command: command, force: force) }
|
let(:app) { described_class.for_cask(cask).first }
|
||||||
|
|
||||||
let(:source_path) { cask.staged_path.join("Caffeine.app") }
|
let(:source_path) { cask.staged_path.join("Caffeine.app") }
|
||||||
let(:target_path) { Hbc.appdir.join("Caffeine.app") }
|
let(:target_path) { Hbc.appdir.join("Caffeine.app") }
|
||||||
|
|
||||||
let(:install_phase) { app.install_phase }
|
let(:install_phase) { app.install_phase(command: command, force: force) }
|
||||||
let(:uninstall_phase) { app.uninstall_phase }
|
let(:uninstall_phase) { app.uninstall_phase(command: command, force: force) }
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
InstallHelper.install_without_artifacts(cask)
|
InstallHelper.install_without_artifacts(cask)
|
||||||
@ -105,8 +105,8 @@ describe Hbc::Artifact::App, :cask do
|
|||||||
|
|
||||||
describe "target is user-owned but contains read-only files" do
|
describe "target is user-owned but contains read-only files" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
system "/usr/bin/touch", "--", "#{target_path}/foo"
|
FileUtils.touch "#{target_path}/foo"
|
||||||
system "/bin/chmod", "--", "0555", target_path
|
FileUtils.chmod 0555, target_path
|
||||||
end
|
end
|
||||||
|
|
||||||
it "overwrites the existing app" do
|
it "overwrites the existing app" do
|
||||||
@ -138,7 +138,7 @@ describe Hbc::Artifact::App, :cask do
|
|||||||
end
|
end
|
||||||
|
|
||||||
after(:each) do
|
after(:each) do
|
||||||
system "/bin/chmod", "--", "0755", target_path
|
FileUtils.chmod 0755, target_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -206,8 +206,8 @@ describe Hbc::Artifact::App, :cask do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "summary" do
|
describe "summary" do
|
||||||
let(:description) { app.summary[:english_description] }
|
let(:description) { app.class.english_description }
|
||||||
let(:contents) { app.summary[:contents] }
|
let(:contents) { app.summarize_installed }
|
||||||
|
|
||||||
it "returns the correct english_description" do
|
it "returns the correct english_description" do
|
||||||
expect(description).to eq("Apps")
|
expect(description).to eq("Apps")
|
||||||
@ -217,14 +217,13 @@ describe Hbc::Artifact::App, :cask do
|
|||||||
it "returns the path to the app" do
|
it "returns the path to the app" do
|
||||||
install_phase
|
install_phase
|
||||||
|
|
||||||
expect(contents).to eq(["#{target_path} (#{target_path.abv})"])
|
expect(contents).to eq("#{target_path} (#{target_path.abv})")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "app is missing" do
|
describe "app is missing" do
|
||||||
it "returns a warning and the supposed path to the app" do
|
it "returns a warning and the supposed path to the app" do
|
||||||
expect(contents.size).to eq(1)
|
expect(contents).to match(/.*Missing App.*: #{target_path}/)
|
||||||
expect(contents[0]).to match(/.*Missing App.*: #{target_path}/)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -26,7 +26,8 @@ describe Hbc::Artifact::Binary, :cask do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "links the binary to the proper directory" do
|
it "links the binary to the proper directory" do
|
||||||
Hbc::Artifact::Binary.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(expected_path).to be_a_symlink
|
expect(expected_path).to be_a_symlink
|
||||||
expect(expected_path.readlink).to exist
|
expect(expected_path.readlink).to exist
|
||||||
@ -45,7 +46,8 @@ describe Hbc::Artifact::Binary, :cask do
|
|||||||
expect(FileUtils).to receive(:chmod)
|
expect(FileUtils).to receive(:chmod)
|
||||||
.with("+x", cask.staged_path.join("naked_non_executable")).and_call_original
|
.with("+x", cask.staged_path.join("naked_non_executable")).and_call_original
|
||||||
|
|
||||||
Hbc::Artifact::Binary.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(expected_path).to be_a_symlink
|
expect(expected_path).to be_a_symlink
|
||||||
expect(expected_path.readlink).to be_executable
|
expect(expected_path.readlink).to be_executable
|
||||||
@ -56,7 +58,8 @@ describe Hbc::Artifact::Binary, :cask do
|
|||||||
FileUtils.touch expected_path
|
FileUtils.touch expected_path
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
Hbc::Artifact::Binary.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
}.to raise_error(Hbc::CaskError)
|
}.to raise_error(Hbc::CaskError)
|
||||||
|
|
||||||
expect(expected_path).not_to be :symlink?
|
expect(expected_path).not_to be :symlink?
|
||||||
@ -65,7 +68,8 @@ describe Hbc::Artifact::Binary, :cask do
|
|||||||
it "clobbers an existing symlink" do
|
it "clobbers an existing symlink" do
|
||||||
expected_path.make_symlink("/tmp")
|
expected_path.make_symlink("/tmp")
|
||||||
|
|
||||||
Hbc::Artifact::Binary.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(File.readlink(expected_path)).not_to eq("/tmp")
|
expect(File.readlink(expected_path)).not_to eq("/tmp")
|
||||||
end
|
end
|
||||||
@ -73,7 +77,8 @@ describe Hbc::Artifact::Binary, :cask do
|
|||||||
it "creates parent directory if it doesn't exist" do
|
it "creates parent directory if it doesn't exist" do
|
||||||
FileUtils.rmdir Hbc.binarydir
|
FileUtils.rmdir Hbc.binarydir
|
||||||
|
|
||||||
Hbc::Artifact::Binary.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(expected_path.exist?).to be true
|
expect(expected_path.exist?).to be true
|
||||||
end
|
end
|
||||||
@ -86,8 +91,10 @@ describe Hbc::Artifact::Binary, :cask do
|
|||||||
}
|
}
|
||||||
|
|
||||||
it "links the binary to the proper directory" do
|
it "links the binary to the proper directory" do
|
||||||
Hbc::Artifact::App.new(cask).install_phase
|
Hbc::Artifact::App.for_cask(cask)
|
||||||
Hbc::Artifact::Binary.new(cask).install_phase
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(expected_path).to be_a_symlink
|
expect(expected_path).to be_a_symlink
|
||||||
expect(expected_path.readlink).to exist
|
expect(expected_path.readlink).to exist
|
||||||
|
@ -2,7 +2,7 @@ describe Hbc::Artifact::Artifact, :cask do
|
|||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-generic-artifact.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-generic-artifact.rb") }
|
||||||
|
|
||||||
let(:install_phase) {
|
let(:install_phase) {
|
||||||
-> { Hbc::Artifact::Artifact.new(cask).install_phase }
|
-> { described_class.for_cask(cask).each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
let(:source_path) { cask.staged_path.join("Caffeine.app") }
|
let(:source_path) { cask.staged_path.join("Caffeine.app") }
|
||||||
@ -12,11 +12,11 @@ describe Hbc::Artifact::Artifact, :cask do
|
|||||||
InstallHelper.install_without_artifacts(cask)
|
InstallHelper.install_without_artifacts(cask)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "with no target" do
|
context "without target" do
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-generic-artifact-no-target.rb") }
|
it "fails to load" do
|
||||||
|
expect {
|
||||||
it "fails to install with no target" do
|
Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-generic-artifact-no-target.rb")
|
||||||
expect(install_phase).to raise_error(Hbc::CaskInvalidError)
|
}.to raise_error(Hbc::CaskInvalidError, /target required for Generic Artifact/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,7 +5,8 @@ describe Hbc::Artifact::NestedContainer, :cask do
|
|||||||
InstallHelper.install_without_artifacts(c)
|
InstallHelper.install_without_artifacts(c)
|
||||||
end
|
end
|
||||||
|
|
||||||
Hbc::Artifact::NestedContainer.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(cask.staged_path.join("MyNestedApp.app")).to be_a_directory
|
expect(cask.staged_path.join("MyNestedApp.app")).to be_a_directory
|
||||||
end
|
end
|
||||||
|
@ -8,7 +8,7 @@ describe Hbc::Artifact::Pkg, :cask do
|
|||||||
|
|
||||||
describe "install_phase" do
|
describe "install_phase" do
|
||||||
it "runs the system installer on the specified pkgs" do
|
it "runs the system installer on the specified pkgs" do
|
||||||
pkg = Hbc::Artifact::Pkg.new(cask, command: fake_system_command)
|
pkg = described_class.for_cask(cask).first
|
||||||
|
|
||||||
expect(fake_system_command).to receive(:run!).with(
|
expect(fake_system_command).to receive(:run!).with(
|
||||||
"/usr/sbin/installer",
|
"/usr/sbin/installer",
|
||||||
@ -17,7 +17,7 @@ describe Hbc::Artifact::Pkg, :cask do
|
|||||||
print_stdout: true,
|
print_stdout: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
pkg.install_phase
|
pkg.install_phase(command: fake_system_command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ describe Hbc::Artifact::Pkg, :cask do
|
|||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-choices.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-choices.rb") }
|
||||||
|
|
||||||
it "passes the choice changes xml to the system installer" do
|
it "passes the choice changes xml to the system installer" do
|
||||||
pkg = Hbc::Artifact::Pkg.new(cask, command: fake_system_command)
|
pkg = described_class.for_cask(cask).first
|
||||||
|
|
||||||
file = double(path: Pathname.new("/tmp/choices.xml"))
|
file = double(path: Pathname.new("/tmp/choices.xml"))
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ describe Hbc::Artifact::Pkg, :cask do
|
|||||||
print_stdout: true,
|
print_stdout: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
pkg.install_phase
|
pkg.install_phase(command: fake_system_command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -11,7 +11,8 @@ describe Hbc::Artifact::PostflightBlock, :cask do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
described_class.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(called).to be true
|
expect(called).to be true
|
||||||
expect(yielded_arg).to be_kind_of(Hbc::DSL::Postflight)
|
expect(yielded_arg).to be_kind_of(Hbc::DSL::Postflight)
|
||||||
@ -30,7 +31,8 @@ describe Hbc::Artifact::PostflightBlock, :cask do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
described_class.new(cask).uninstall_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.uninstall_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(called).to be true
|
expect(called).to be true
|
||||||
expect(yielded_arg).to be_kind_of(Hbc::DSL::UninstallPostflight)
|
expect(yielded_arg).to be_kind_of(Hbc::DSL::UninstallPostflight)
|
||||||
|
@ -11,7 +11,8 @@ describe Hbc::Artifact::PreflightBlock, :cask do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
described_class.new(cask).install_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(called).to be true
|
expect(called).to be true
|
||||||
expect(yielded_arg).to be_kind_of Hbc::DSL::Preflight
|
expect(yielded_arg).to be_kind_of Hbc::DSL::Preflight
|
||||||
@ -30,7 +31,8 @@ describe Hbc::Artifact::PreflightBlock, :cask do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
described_class.new(cask).uninstall_phase
|
described_class.for_cask(cask)
|
||||||
|
.each { |artifact| artifact.uninstall_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect(called).to be true
|
expect(called).to be true
|
||||||
expect(yielded_arg).to be_kind_of Hbc::DSL::UninstallPreflight
|
expect(yielded_arg).to be_kind_of Hbc::DSL::UninstallPreflight
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
describe Hbc::Artifact::Suite, :cask do
|
describe Hbc::Artifact::Suite, :cask do
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-suite.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-suite.rb") }
|
||||||
|
|
||||||
let(:install_phase) { -> { Hbc::Artifact::Suite.new(cask).install_phase } }
|
let(:install_phase) {
|
||||||
|
-> { described_class.for_cask(cask).each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) } }
|
||||||
|
}
|
||||||
|
|
||||||
let(:target_path) { Hbc.appdir.join("Caffeine") }
|
let(:target_path) { Hbc.appdir.join("Caffeine") }
|
||||||
let(:source_path) { cask.staged_path.join("Caffeine") }
|
let(:source_path) { cask.staged_path.join("Caffeine") }
|
||||||
|
@ -3,7 +3,7 @@ describe Hbc::Artifact::App, :cask do
|
|||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-two-apps-correct.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-two-apps-correct.rb") }
|
||||||
|
|
||||||
let(:install_phase) {
|
let(:install_phase) {
|
||||||
-> { Hbc::Artifact::App.new(cask).install_phase }
|
-> { described_class.for_cask(cask).each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
let(:source_path_mini) { cask.staged_path.join("Caffeine Mini.app") }
|
let(:source_path_mini) { cask.staged_path.join("Caffeine Mini.app") }
|
||||||
|
@ -2,7 +2,7 @@ describe Hbc::Artifact::Zap, :cask do
|
|||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-installable.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-installable.rb") }
|
||||||
|
|
||||||
let(:zap_artifact) {
|
let(:zap_artifact) {
|
||||||
Hbc::Artifact::Zap.new(cask)
|
described_class.for_cask(cask).first
|
||||||
}
|
}
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
shared_examples "#uninstall_phase or #zap_phase" do
|
shared_examples "#uninstall_phase or #zap_phase" do
|
||||||
let(:artifact_name) { described_class.artifact_name }
|
let(:artifact_dsl_key) { described_class.dsl_key }
|
||||||
let(:artifact) { described_class.new(cask, command: fake_system_command) }
|
let(:artifact) { described_class.for_cask(cask).first }
|
||||||
let(:fake_system_command) { Hbc::FakeSystemCommand }
|
let(:fake_system_command) { Hbc::FakeSystemCommand }
|
||||||
|
|
||||||
subject { artifact.public_send(:"#{artifact_name}_phase") }
|
subject { artifact.public_send(:"#{artifact_dsl_key}_phase", command: fake_system_command) }
|
||||||
|
|
||||||
context "using :launchctl" do
|
context "using :launchctl" do
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-launchctl.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-launchctl.rb") }
|
||||||
let(:launchctl_list_cmd) { %w[/bin/launchctl list my.fancy.package.service] }
|
let(:launchctl_list_cmd) { %w[/bin/launchctl list my.fancy.package.service] }
|
||||||
let(:launchctl_remove_cmd) { %w[/bin/launchctl remove my.fancy.package.service] }
|
let(:launchctl_remove_cmd) { %w[/bin/launchctl remove my.fancy.package.service] }
|
||||||
let(:unknown_response) { "launchctl list returned unknown response\n" }
|
let(:unknown_response) { "launchctl list returned unknown response\n" }
|
||||||
@ -61,7 +61,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
context "using :pkgutil" do
|
context "using :pkgutil" do
|
||||||
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
|
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
|
||||||
|
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-pkgutil.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-pkgutil.rb") }
|
||||||
|
|
||||||
let(:main_pkg_id) { "my.fancy.package.main" }
|
let(:main_pkg_id) { "my.fancy.package.main" }
|
||||||
let(:agent_pkg_id) { "my.fancy.package.agent" }
|
let(:agent_pkg_id) { "my.fancy.package.agent" }
|
||||||
@ -85,7 +85,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "using :kext" do
|
context "using :kext" do
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-kext.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-kext.rb") }
|
||||||
let(:kext_id) { "my.fancy.package.kernelextension" }
|
let(:kext_id) { "my.fancy.package.kernelextension" }
|
||||||
|
|
||||||
it "is supported" do
|
it "is supported" do
|
||||||
@ -110,7 +110,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "using :quit" do
|
context "using :quit" do
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-quit.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-quit.rb") }
|
||||||
let(:bundle_id) { "my.fancy.package.app" }
|
let(:bundle_id) { "my.fancy.package.app" }
|
||||||
let(:quit_application_script) do
|
let(:quit_application_script) do
|
||||||
%Q(tell application id "#{bundle_id}" to quit)
|
%Q(tell application id "#{bundle_id}" to quit)
|
||||||
@ -130,7 +130,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "using :signal" do
|
context "using :signal" do
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-signal.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-signal.rb") }
|
||||||
let(:bundle_id) { "my.fancy.package.app" }
|
let(:bundle_id) { "my.fancy.package.app" }
|
||||||
let(:signals) { %w[TERM KILL] }
|
let(:signals) { %w[TERM KILL] }
|
||||||
let(:unix_pids) { [12_345, 67_890] }
|
let(:unix_pids) { [12_345, 67_890] }
|
||||||
@ -170,10 +170,10 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
|
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-#{directive}.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-#{directive}.rb") }
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
allow_any_instance_of(Hbc::Artifact::UninstallBase).to receive(:trash_paths)
|
allow_any_instance_of(Hbc::Artifact::AbstractUninstall).to receive(:trash_paths)
|
||||||
.and_wrap_original do |method, *args|
|
.and_wrap_original do |method, *args|
|
||||||
result = method.call(*args)
|
result = method.call(*args)
|
||||||
FileUtils.rm_rf result.stdout.split("\0")
|
FileUtils.rm_rf result.stdout.split("\0")
|
||||||
@ -196,7 +196,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
|
|
||||||
context "using :rmdir" do
|
context "using :rmdir" do
|
||||||
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
|
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-rmdir.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-rmdir.rb") }
|
||||||
let(:empty_directory) { Pathname.new("#{TEST_TMPDIR}/empty_directory_path") }
|
let(:empty_directory) { Pathname.new("#{TEST_TMPDIR}/empty_directory_path") }
|
||||||
let(:ds_store) { empty_directory.join(".DS_Store") }
|
let(:ds_store) { empty_directory.join(".DS_Store") }
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
[:script, :early_script].each do |script_type|
|
[:script, :early_script].each do |script_type|
|
||||||
context "using #{script_type.inspect}" do
|
context "using #{script_type.inspect}" do
|
||||||
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
|
let(:fake_system_command) { Hbc::NeverSudoSystemCommand }
|
||||||
let(:token) { "with-#{artifact_name}-#{script_type}".tr("_", "-") }
|
let(:token) { "with-#{artifact_dsl_key}-#{script_type}".tr("_", "-") }
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/#{token}.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/#{token}.rb") }
|
||||||
let(:script_pathname) { cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool") }
|
let(:script_pathname) { cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool") }
|
||||||
|
|
||||||
@ -250,7 +250,7 @@ shared_examples "#uninstall_phase or #zap_phase" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "using :login_item" do
|
context "using :login_item" do
|
||||||
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_name}-login-item.rb") }
|
let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-#{artifact_dsl_key}-login-item.rb") }
|
||||||
|
|
||||||
it "is supported" do
|
it "is supported" do
|
||||||
Hbc::FakeSystemCommand.expects_command(
|
Hbc::FakeSystemCommand.expects_command(
|
||||||
|
@ -265,19 +265,14 @@ describe Hbc::Audit, :cask do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "generic artifact checks" do
|
describe "generic artifact checks" do
|
||||||
context "with no target" do
|
|
||||||
let(:cask_token) { "generic-artifact-no-target" }
|
|
||||||
it { is_expected.to fail_with(/target required for generic artifact/) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with relative target" do
|
context "with relative target" do
|
||||||
let(:cask_token) { "generic-artifact-relative-target" }
|
let(:cask_token) { "generic-artifact-relative-target" }
|
||||||
it { is_expected.to fail_with(/target must be absolute path for generic artifact/) }
|
it { is_expected.to fail_with(/target must be absolute path for Generic Artifact/) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with absolute target" do
|
context "with absolute target" do
|
||||||
let(:cask_token) { "generic-artifact-absolute-target" }
|
let(:cask_token) { "generic-artifact-absolute-target" }
|
||||||
it { should_not fail_with(/target required for generic artifact/) }
|
it { should_not fail_with(/target required for Generic Artifact/) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ describe Hbc::CLI::Info, :cask do
|
|||||||
==> Name
|
==> Name
|
||||||
None
|
None
|
||||||
==> Artifacts
|
==> Artifacts
|
||||||
Caffeine.app (app)
|
Caffeine.app (App)
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ describe Hbc::CLI::Info, :cask do
|
|||||||
==> Name
|
==> Name
|
||||||
None
|
None
|
||||||
==> Artifacts
|
==> Artifacts
|
||||||
Caffeine.app (app)
|
Caffeine.app (App)
|
||||||
local-transmission: 2.61
|
local-transmission: 2.61
|
||||||
http://example.com/local-transmission
|
http://example.com/local-transmission
|
||||||
Not installed
|
Not installed
|
||||||
@ -32,7 +32,7 @@ describe Hbc::CLI::Info, :cask do
|
|||||||
==> Name
|
==> Name
|
||||||
None
|
None
|
||||||
==> Artifacts
|
==> Artifacts
|
||||||
Transmission.app (app)
|
Transmission.app (App)
|
||||||
EOS
|
EOS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ describe Hbc::CLI::Info, :cask do
|
|||||||
==> Name
|
==> Name
|
||||||
None
|
None
|
||||||
==> Artifacts
|
==> Artifacts
|
||||||
Caffeine.app (app)
|
Caffeine.app (App)
|
||||||
==> Caveats
|
==> Caveats
|
||||||
Here are some things you might want to know.
|
Here are some things you might want to know.
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ describe Hbc::CLI::Info, :cask do
|
|||||||
==> Name
|
==> Name
|
||||||
None
|
None
|
||||||
==> Artifacts
|
==> Artifacts
|
||||||
Caffeine.app (app)
|
Caffeine.app (App)
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,7 +48,8 @@ describe Hbc::CLI::List, :cask do
|
|||||||
it "lists the installed files for those Casks" do
|
it "lists the installed files for those Casks" do
|
||||||
casks.each(&InstallHelper.method(:install_without_artifacts_with_caskfile))
|
casks.each(&InstallHelper.method(:install_without_artifacts_with_caskfile))
|
||||||
|
|
||||||
Hbc::Artifact::App.new(transmission).install_phase
|
Hbc::Artifact::App.for_cask(transmission)
|
||||||
|
.each { |artifact| artifact.install_phase(command: Hbc::NeverSudoSystemCommand, force: false) }
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
Hbc::CLI::List.run("local-transmission", "local-caffeine")
|
Hbc::CLI::List.run("local-transmission", "local-caffeine")
|
||||||
|
@ -186,12 +186,12 @@ describe Hbc::DSL, :cask do
|
|||||||
app "Bar.app"
|
app "Bar.app"
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Array(cask.artifacts[:app])).to eq([["Foo.app"], ["Bar.app"]])
|
expect(cask.artifacts[:app].map(&:to_s)).to eq(["Foo.app (App)", "Bar.app (App)"])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allow app stanzas to be empty" do
|
it "allow app stanzas to be empty" do
|
||||||
cask = Hbc::Cask.new("cask-with-no-apps")
|
cask = Hbc::Cask.new("cask-with-no-apps")
|
||||||
expect(Array(cask.artifacts[:app])).to eq([])
|
expect(cask.artifacts[:app]).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ describe Hbc::DSL, :cask do
|
|||||||
pkg "Bar.pkg"
|
pkg "Bar.pkg"
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Array(cask.artifacts[:pkg])).to eq([["Foo.pkg"], ["Bar.pkg"]])
|
expect(cask.artifacts[:pkg].map(&:to_s)).to eq(["Foo.pkg (Pkg)", "Bar.pkg (Pkg)"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -471,10 +471,10 @@ describe Hbc::DSL, :cask do
|
|||||||
let(:token) { "with-installer-script" }
|
let(:token) { "with-installer-script" }
|
||||||
|
|
||||||
it "allows installer script to be specified" do
|
it "allows installer script to be specified" do
|
||||||
expect(cask.artifacts[:installer].first.script[:executable]).to eq("/usr/bin/true")
|
expect(cask.artifacts[:installer].first.path).to eq(Pathname("/usr/bin/true"))
|
||||||
expect(cask.artifacts[:installer].first.script[:args]).to eq(["--flag"])
|
expect(cask.artifacts[:installer].first.args[:args]).to eq(["--flag"])
|
||||||
expect(cask.artifacts[:installer].to_a[1].script[:executable]).to eq("/usr/bin/false")
|
expect(cask.artifacts[:installer].to_a[1].path).to eq(Pathname("/usr/bin/false"))
|
||||||
expect(cask.artifacts[:installer].to_a[1].script[:args]).to eq(["--flag"])
|
expect(cask.artifacts[:installer].to_a[1].args[:args]).to eq(["--flag"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -482,7 +482,9 @@ describe Hbc::DSL, :cask do
|
|||||||
let(:token) { "with-installer-manual" }
|
let(:token) { "with-installer-manual" }
|
||||||
|
|
||||||
it "allows installer manual to be specified" do
|
it "allows installer manual to be specified" do
|
||||||
expect(cask.artifacts[:installer].first.manual).to eq("Caffeine.app")
|
installer = cask.artifacts[:installer].first
|
||||||
|
expect(installer).to be_a(Hbc::Artifact::Installer::ManualInstaller)
|
||||||
|
expect(installer.path).to eq(cask.staged_path.join("Caffeine.app"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -492,7 +494,7 @@ describe Hbc::DSL, :cask do
|
|||||||
let(:token) { "stage-only" }
|
let(:token) { "stage-only" }
|
||||||
|
|
||||||
it "allows stage_only stanza to be specified" do
|
it "allows stage_only stanza to be specified" do
|
||||||
expect(cask.artifacts[:stage_only].first).to eq([true])
|
expect(cask.artifacts[:stage_only]).not_to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -518,7 +520,7 @@ describe Hbc::DSL, :cask do
|
|||||||
let(:token) { "appdir-interpolation" }
|
let(:token) { "appdir-interpolation" }
|
||||||
|
|
||||||
it "is allowed" do
|
it "is allowed" do
|
||||||
expect(cask.artifacts[:binary].first).to eq(["#{Hbc.appdir}/some/path"])
|
expect(cask.artifacts[:binary].first.source).to eq(Hbc.appdir/"some/path")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -531,7 +533,7 @@ describe Hbc::DSL, :cask do
|
|||||||
binary "#{appdir}/some/path"
|
binary "#{appdir}/some/path"
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(cask.artifacts[:binary].first).to eq(["#{original_appdir}/some/path"])
|
expect(cask.artifacts[:binary].first.source).to eq(original_appdir/"some/path")
|
||||||
ensure
|
ensure
|
||||||
Hbc.appdir = original_appdir
|
Hbc.appdir = original_appdir
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user