prefpane support; artifact refactor

= New Concept: Cask::Artifact

An Artifact is a file in an extacted container for which homebrew-cask
should take some sort of action on install/uninstall.

== Current artifacts:

 - App: link/unlink to ~/Applications
 - Pkg: install/uninstall (with sudo)
 - Prefpane: link/unlink to ~/Library/PreferencePanes

= New Feature: Preference Pane Handling

Specifying `prefpane 'MyApp.prefPane'` in a Cask causes it to be linked
on install to the correct location for it to show up in System
Preferences.

refs #69

= Removed Commands: linkapps/unlinkapps

These were old and mostly unused and don't really make much sense when
linking/unlinking happens automatically in the install process.

= Changed Behavior: stricter relative pathname requirement

With this refactor, we remove the fuzzy searching for a file in an
extracted container when that file was referenced from `link`
or `install`. There may be some casks that need to be updated due to
this change.
This commit is contained in:
phinze 2013-09-23 09:32:46 -05:00
parent ed7358cf32
commit c244385eb2
29 changed files with 409 additions and 372 deletions

7
Casks/hazel.rb Normal file
View file

@ -0,0 +1,7 @@
class Hazel < Cask
url 'https://s3.amazonaws.com/Noodlesoft/Hazel-3.1.5.dmg'
homepage 'http://www.noodlesoft.com/hazel.php'
version '3.1.5'
sha1 'a020aa443ed2b4812d72d7da802177c6e077c048'
prefpane 'Hazel.prefPane'
end

7
Casks/tv-shows.rb Normal file
View file

@ -0,0 +1,7 @@
class TvShows < Cask
url 'http://tvshowsapp.com/TVShows.zip'
homepage 'http://tvshowsapp.com/'
version 'latest'
no_checksum
prefpane 'TvShows.prefpane'
end

View file

@ -4,7 +4,7 @@ HOMEBREW_CACHE_CASKS = HOMEBREW_CACHE.join('Casks')
class Cask; end
require 'cask/app_linker'
require 'cask/artifact'
require 'cask/audit'
require 'cask/auditor'
require 'cask/checkable'
@ -16,8 +16,8 @@ require 'cask/exceptions'
require 'cask/fetcher'
require 'cask/installer'
require 'cask/link_checker'
require 'cask/locations'
require 'cask/pkg'
require 'cask/pkg_installer'
require 'cask/scopes'
require 'cask/system_command'
@ -25,36 +25,9 @@ require 'plist/parser'
class Cask
include Cask::DSL
include Cask::Locations
include Cask::Scopes
def self.tapspath
HOMEBREW_PREFIX.join "Library", "Taps"
end
def self.caskroom
@@caskroom ||= Pathname('/opt/homebrew-cask/Caskroom')
end
def self.caskroom=(caskroom)
@@caskroom = caskroom
end
def self.appdir
@appdir ||= Pathname.new(File.expand_path("~/Applications"))
end
def self.appdir=(_appdir)
@appdir = _appdir
end
def self.default_tap
@default_tap ||= 'phinze-cask'
end
def self.default_tap=(_tap)
@default_tap = _tap
end
def self._file_source?(requested_cask)
File.file?(requested_cask)
end
@ -76,24 +49,6 @@ class Cask
appdir.mkpath unless appdir.exist?
end
def self.path(cask_title)
if cask_title.include?('/')
cask_with_tap = cask_title
else
cask_with_tap = all_titles.detect { |tap_and_title|
_, title = tap_and_title.split('/')
title == cask_title
}
end
if cask_with_tap
tap, cask = cask_with_tap.split('/')
tapspath.join(tap, 'Casks', "#{cask}.rb")
else
tapspath.join(default_tap, 'Casks', "#{cask_title}.rb")
end
end
def self._load_from_tap(cask_title)
if cask_title.include?('/')
cask_with_tap = cask_title
@ -161,14 +116,6 @@ class Cask
destination_path.exist?
end
def linkable_apps
linkables.map { |app| Pathname.glob("#{destination_path}/**/#{app}").first }
end
def installers
installables.map { |pkg| Pathname.glob("#{destination_path}/**/#{pkg}").first }
end
def to_s
@title
end

View file

@ -1,33 +0,0 @@
class Cask
class AppLinker
def initialize(cask)
@cask = cask
end
def link
@cask.linkable_apps.each { |app| link_app(app) }
end
def unlink
@cask.linkable_apps.each { |app| unlink_app(app) }
end
def unlink_app(app)
app_path = Cask.appdir.join(app.basename)
if app_path.exist? && app_path.symlink?
ohai "Removing link: #{app_path}"
app_path.delete
end
end
def link_app(app)
app_path = Cask.appdir.join(app.basename)
if app_path.directory? && !app_path.symlink?
ohai "It seems there is already an app at #{app_path}; not linking."
return
end
ohai "Linking #{app.basename} to #{app_path}"
system %Q(/bin/ln -hfs "#{app}" "#{app_path}")
end
end
end

21
lib/cask/artifact.rb Normal file
View file

@ -0,0 +1,21 @@
module Cask::Artifact; end
require 'cask/artifact/base'
require 'cask/artifact/app'
require 'cask/artifact/pkg'
require 'cask/artifact/prefpane'
module Cask::Artifact
def self.artifacts
[
Cask::Artifact::App,
Cask::Artifact::Pkg,
Cask::Artifact::Prefpane,
]
end
def self.for_cask(cask)
artifacts.select { |artifact| artifact.me?(cask) }
end
end

41
lib/cask/artifact/app.rb Normal file
View file

@ -0,0 +1,41 @@
class Cask::Artifact::App < Cask::Artifact::Base
def self.me?(cask)
cask.artifacts[:link].any?
end
def install
@cask.artifacts[:link].each { |app| link(app) }
end
def uninstall
@cask.artifacts[:link].each { |app| unlink(app) }
end
def link(app_relative_path)
source = @cask.destination_path.join(app_relative_path)
target = Cask.appdir.join(source.basename)
return unless preflight_checks(source, target)
ohai "Linking #{source.basename} to #{target}"
@command.run('ln', :args => ['-hfs', source, target])
end
def preflight_checks(source, target)
if target.directory? && !target.symlink?
ohai "It seems there is already an app at #{target}; not linking."
return false
end
unless source.exist?
raise "it seems the symlink source is not there: #{source}"
end
true
end
def unlink(app_relative_path)
linked_path = Cask.appdir.join(Pathname(app_relative_path).basename)
if linked_path.exist? && linked_path.symlink?
ohai "Removing link: #{linked_path}"
linked_path.delete
end
end
end

View file

@ -0,0 +1,6 @@
class Cask::Artifact::Base
def initialize(cask, command=Cask::SystemCommand)
@cask = cask
@command = command
end
end

59
lib/cask/artifact/pkg.rb Normal file
View file

@ -0,0 +1,59 @@
class Cask::Artifact::Pkg < Cask::Artifact::Base
def self.me?(cask)
cask.artifacts[:install].any?
end
def install
@cask.artifacts[:install].each { |pkg| run_installer(pkg) }
end
def uninstall
@cask.artifacts[:uninstall].each { |opts| manually_uninstall(opts) }
end
def run_installer(pkg_relative_path)
ohai "Running installer for #{@cask}; your password may be necessary."
@command.run("installer", {
:sudo => true,
:args => %W[-pkg #{@cask.destination_path.join(pkg_relative_path)} -target /],
:print => true
})
end
def manually_uninstall(uninstall_options)
ohai "Running uninstall process for #{@cask}; your password may be necessary."
if uninstall_options.key? :script
@command.run(
@cask.destination_path.join(uninstall_options[:script]),
uninstall_options.merge(:sudo => true, :print => true)
)
end
if uninstall_options.key? :kext
[*uninstall_options[:kext]].each do |kext|
ohai "Unloading kernel extension #{kext}"
@command.run('kextunload', :args => ['-b', kext], :sudo => true)
end
end
if uninstall_options.key? :pkgutil
pkgs = Cask::Pkg.all_matching(uninstall_options[:pkgutil], @command)
pkgs.each(&:uninstall)
end
if uninstall_options.key? :launchctl
[*uninstall_options[:launchctl]].each do |service|
ohai "Removing launchctl service #{service}"
@command.run('launchctl', :args => ['remove', service], :sudo => true)
end
end
if uninstall_options.key? :files
uninstall_options[:files].each do |file|
ohai "Removing file #{file}"
@command.run('rm', :args => ['-rf', file], :sudo => true)
end
end
end
end

View file

@ -0,0 +1,41 @@
class Cask::Artifact::Prefpane < Cask::Artifact::Base
def self.me?(cask)
cask.artifacts[:prefpane].any?
end
def install
@cask.artifacts[:prefpane].each { |prefpane| link(prefpane) }
end
def uninstall
@cask.artifacts[:prefpane].each { |prefpane| unlink(prefpane) }
end
def link(prefpane_relative_path)
source = @cask.destination_path.join(prefpane_relative_path)
target = Cask.prefpanedir.join(source.basename)
return unless preflight_checks(source, target)
ohai "Linking prefPane #{source.basename} to #{target}"
@command.run('ln', :args => ['-hfs', source, target])
end
def preflight_checks(source, target)
if target.directory? && !target.symlink?
ohai "It seems there is already an prefpane at #{target}; not linking."
false
end
unless source.exist?
raise "it seems the symlink source is not there: #{source}"
end
true
end
def unlink(prefpane_relative_path)
linked_path = Cask.prefpanedir.join(Pathname(prefpane_relative_path).basename)
if linked_path.exist? && linked_path.symlink?
ohai "Removing prefPane link: #{linked_path}"
linked_path.delete
end
end
end

View file

@ -11,11 +11,9 @@ require 'cask/cli/edit'
require 'cask/cli/home'
require 'cask/cli/info'
require 'cask/cli/install'
require 'cask/cli/linkapps'
require 'cask/cli/list'
require 'cask/cli/search'
require 'cask/cli/uninstall'
require 'cask/cli/unlinkapps'
class Cask::CLI
def self.commands

View file

@ -6,8 +6,6 @@ class Cask::CLI::Install
begin
cask = Cask.load(cask_name)
Cask::Installer.new(cask).install(force)
Cask::AppLinker.new(cask).link
Cask::PkgInstaller.new(cask).install
rescue CaskError => e
onoe e
end

View file

@ -1,12 +0,0 @@
class Cask::CLI::Linkapps
def self.run(*args)
casks_to_link = args.empty? ? Cask.installed : args
casks_to_link.each do |cask_name|
Cask::AppLinker.new(Cask.load(cask_name)).link
end
end
def self.help
"makes a symlink from all cask-installed .app files into ~/Applications"
end
end

View file

@ -4,8 +4,6 @@ class Cask::CLI::Uninstall
casks = cask_names.map { |cn| Cask.load(cn) }
casks.each do |cask|
raise CaskNotInstalledError.new(cask) unless cask.installed?
Cask::PkgInstaller.new(cask).uninstall
Cask::AppLinker.new(cask).unlink
Cask::Installer.new(cask).uninstall
end
rescue CaskError => e

View file

@ -1,12 +0,0 @@
class Cask::CLI::Unlinkapps
def self.run(*args)
casks_to_link = args.empty? ? Cask.installed : args
casks_to_link.each do |cask_name|
Cask::AppLinker.new(Cask.load(cask_name)).unlink
end
end
def self.help
"removes symlinks from cask-installed .app files from ~/Applications"
end
end

View file

@ -14,7 +14,8 @@ class Cask::Container::Criteria
@imageinfo ||= @command.run(
'hdiutil',
:args => ['imageinfo', path],
:stderr => :silence
:stderr => :silence,
:print => false
)
end
end

View file

@ -14,11 +14,7 @@ module Cask::DSL
def sums; self.class.sums || []; end
def linkables; self.class.linkables || {}; end
def installables; self.class.installables || []; end
def uninstallables; self.class.uninstallables || []; end
def artifacts; self.class.artifacts; end
def caveats; ''; end
@ -35,31 +31,21 @@ module Cask::DSL
@version ||= version
end
def linkables
@linkables ||= Set.new
def artifacts
@artifacts ||= Hash.new { |hash, key| hash[key] = Set.new }
end
def link(*args)
# handle old-style casks using link :app, 'Foo.app'
args.shift if args.first.is_a? Symbol
ARTIFACT_TYPES = [
:link,
:prefpane,
:install,
:uninstall
]
linkables.merge args
end
def installables
@installables ||= Set.new
end
def install(*files)
installables.merge files
end
def uninstallables
@uninstallables ||= Set.new
end
def uninstall(options)
uninstallables.merge [options]
ARTIFACT_TYPES.each do |type|
define_method(type) do |*args|
artifacts[type].merge(args)
end
end
attr_reader :sums

View file

@ -11,25 +11,56 @@ class Cask::Installer
raise CaskAlreadyInstalledError.new(@cask)
end
download = Cask::Download.new(@cask)
downloaded_path = download.perform
FileUtils.mkdir_p @cask.destination_path
container = Cask::Container.for_path(downloaded_path, @command)
unless container
raise "uh oh, could not identify container for #{downloaded_path}"
end
container.new(@cask, downloaded_path, @command).extract
download
extract_container
install_artifacts
ohai "Success! #{@cask} installed to #{@cask.destination_path}"
print_caveats
end
def download
download = Cask::Download.new(@cask)
@downloaded_path = download.perform
end
def extract_container
FileUtils.mkdir_p @cask.destination_path
container = Cask::Container.for_path(@downloaded_path, @command)
unless container
raise "uh oh, could not identify container for #{@downloaded_path}"
end
container.new(@cask, @downloaded_path, @command).extract
end
def install_artifacts
artifacts = Cask::Artifact.for_cask(@cask)
artifacts.each do |artifact|
artifact.new(@cask, @command).install
end
end
def print_caveats
unless @cask.caveats.empty?
ohai 'Caveats', @cask.caveats
end
end
def uninstall
uninstall_artifacts
purge_files
end
def uninstall_artifacts
artifacts = Cask::Artifact.for_cask(@cask)
artifacts.each do |artifact|
artifact.new(@cask, @command).uninstall
end
end
def purge_files
@cask.destination_path.rmtree
end
end

61
lib/cask/locations.rb Normal file
View file

@ -0,0 +1,61 @@
module Cask::Locations
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def tapspath
HOMEBREW_PREFIX.join "Library", "Taps"
end
def caskroom
@@caskroom ||= Pathname('/opt/homebrew-cask/Caskroom')
end
def caskroom=(caskroom)
@@caskroom = caskroom
end
def appdir
@appdir ||= Pathname.new('~/Applications').expand_path
end
def appdir=(_appdir)
@appdir = _appdir
end
def prefpanedir
@prefpanedir ||= Pathname.new('~/Library/PreferencePanes').expand_path
end
def prefpanedir=(_prefpanedir)
@prefpanedir = _prefpanedir
end
def default_tap
@default_tap ||= 'phinze-cask'
end
def default_tap=(_tap)
@default_tap = _tap
end
def path(cask_title)
if cask_title.include?('/')
cask_with_tap = cask_title
else
cask_with_tap = all_titles.detect { |tap_and_title|
_, title = tap_and_title.split('/')
title == cask_title
}
end
if cask_with_tap
tap, cask = cask_with_tap.split('/')
tapspath.join(tap, 'Casks', "#{cask}.rb")
else
tapspath.join(default_tap, 'Casks', "#{cask_title}.rb")
end
end
end
end

View file

@ -1,55 +0,0 @@
class Cask::PkgInstaller
def initialize(cask, command=Cask::SystemCommand)
@cask = cask
@command = command
end
def install
@cask.installers.each do |installer|
ohai "Running installer for #{@cask}; your password may be necessary."
@command.run("installer", {
:sudo => true,
:args => %W[-pkg #{installer} -target /],
:print => true
})
end
end
def uninstall
@cask.uninstallables.each do |uninstall_options|
ohai "Running uninstall process for #{@cask}; your password may be necessary."
if uninstall_options.key? :script
@command.run(
@cask.destination_path.join(uninstall_options[:script]),
uninstall_options.merge(:sudo => true, :print => true)
)
end
if uninstall_options.key? :kext
[*uninstall_options[:kext]].each do |kext|
ohai "Unloading kernel extension #{kext}"
@command.run('kextunload', :args => ['-b', kext], :sudo => true)
end
end
if uninstall_options.key? :pkgutil
pkgs = Cask::Pkg.all_matching(uninstall_options[:pkgutil], @command)
pkgs.each(&:uninstall)
end
if uninstall_options.key? :launchctl
[*uninstall_options[:launchctl]].each do |service|
ohai "Removing launchctl service #{service}"
@command.run('launchctl', :args => ['remove', service], :sudo => true)
end
end
if uninstall_options.key? :files
uninstall_options[:files].each do |file|
ohai "Removing file #{file}"
@command.run('rm', :args => ['-rf', file], :sudo => true)
end
end
end
end
end

View file

@ -1,62 +0,0 @@
require 'test_helper'
describe Cask::AppLinker do
describe 'linkapps' do
before do
@caffeine = Cask.load('local-caffeine')
shutup { Cask::Installer.new(@caffeine).install }
@app = @caffeine.destination_path/'Caffeine.app'
end
it "works with an application in the root directory" do
shutup do
Cask::AppLinker.new(@caffeine).link
end
TestHelper.valid_alias?(Cask.appdir/'Caffeine.app').must_equal true
end
it "works with an application in a subdir" do
appsubdir = @caffeine.destination_path/'subdir'
appsubdir.mkpath
FileUtils.mv @app, appsubdir
appinsubdir = appsubdir/'Caffeine.app'
shutup do
Cask::AppLinker.new(@caffeine).link
end
TestHelper.valid_alias?(Cask.appdir/'Caffeine.app').must_equal true
end
it "only uses linkables when they are specified" do
FileUtils.cp_r @app, @app.sub('Caffeine.app', 'CaffeineAgain.app')
shutup do
Cask::AppLinker.new(@caffeine).link
end
TestHelper.valid_alias?(Cask.appdir/'Caffeine.app').must_equal true
TestHelper.valid_alias?(Cask.appdir/'CaffeineAgain.app').must_equal false
end
it "avoids clobbering an existing app by linking over it" do
(Cask.appdir/'Caffeine.app').mkpath
TestHelper.must_output(self, lambda {
Cask::AppLinker.new(@caffeine).link
}, "==> It seems there is already an app at #{Cask.appdir.join('Caffeine.app')}; not linking.")
(Cask.appdir/'Caffeine.app').wont_be :symlink?
end
it "happily clobbers an existing symlink" do
(Cask.appdir/'Caffeine.app').make_symlink('/tmp')
TestHelper.must_output(self, lambda {
Cask::AppLinker.new(@caffeine).link
}, "==> Linking Caffeine.app to #{Cask.appdir.join('Caffeine.app')}")
File.readlink(Cask.appdir/'Caffeine.app').wont_equal '/tmp'
end
end
end

View file

@ -0,0 +1,83 @@
require 'test_helper'
describe Cask::Artifact::App do
let(:local_caffeine) {
Cask.load('local-caffeine').tap do |cask|
TestHelper.install_without_artifacts(cask)
end
}
describe 'install' do
it "links the noted applications to the proper directory" do
cask = local_caffeine
shutup do
Cask::Artifact::App.new(cask).install
end
TestHelper.valid_alias?(Cask.appdir/'Caffeine.app').must_equal true
end
it "works with an application in a subdir" do
SubDirCask = Class.new(Cask)
SubDirCask.class_eval do
url TestHelper.local_binary('caffeine.zip')
homepage 'http://example.com/local-caffeine'
version '1.2.3'
sha1 'd2fbdad1619934313026fc831e6c6e3dd97ac030'
link 'subdir/Caffeine.app'
end
subdir_cask = SubDirCask.new.tap do |cask|
TestHelper.install_without_artifacts(cask)
end
appsubdir = (subdir_cask.destination_path/'subdir').tap(&:mkpath)
FileUtils.mv((subdir_cask.destination_path/'Caffeine.app'), appsubdir)
shutup do
Cask::Artifact::App.new(subdir_cask).install
end
TestHelper.valid_alias?(Cask.appdir/'Caffeine.app').must_equal true
end
it "only uses linkables when they are specified" do
cask = local_caffeine
app_path = cask.destination_path.join('Caffeine.app')
FileUtils.cp_r app_path, app_path.sub('Caffeine.app', 'CaffeineAgain.app')
shutup do
Cask::Artifact::App.new(cask).install
end
TestHelper.valid_alias?(Cask.appdir/'Caffeine.app').must_equal true
TestHelper.valid_alias?(Cask.appdir/'CaffeineAgain.app').must_equal false
end
it "avoids clobbering an existing app by linking over it" do
cask = local_caffeine
(Cask.appdir/'Caffeine.app').mkpath
TestHelper.must_output(self, lambda {
Cask::Artifact::App.new(cask).install
}, "==> It seems there is already an app at #{Cask.appdir.join('Caffeine.app')}; not linking.")
(Cask.appdir/'Caffeine.app').wont_be :symlink?
end
it "happily clobbers an existing symlink" do
cask = local_caffeine
(Cask.appdir/'Caffeine.app').make_symlink('/tmp')
TestHelper.must_output(self, lambda {
Cask::Artifact::App.new(cask).install
}, "==> Linking Caffeine.app to #{Cask.appdir.join('Caffeine.app')}")
File.readlink(Cask.appdir/'Caffeine.app').wont_equal '/tmp'
end
end
end

View file

@ -1,22 +1,22 @@
require 'test_helper'
describe Cask::PkgInstaller do
describe Cask::Artifact::Pkg do
before {
@cask = Cask.load('with-installable')
shutup do
Cask::Installer.new(@cask).install
TestHelper.install_without_artifacts(@cask)
end
}
describe 'install' do
it 'runs the system installer on the specified pkgs' do
pkg_installer = Cask::PkgInstaller.new(@cask, Cask::FakeSystemCommand)
pkg = Cask::Artifact::Pkg.new(@cask, Cask::FakeSystemCommand)
expected_command = "sudo 'installer' '-pkg' '#{@cask.destination_path/'MyFancyPkg'/'Fancy.pkg'}' '-target' '/' 2>&1"
Cask::FakeSystemCommand.fake_response_for(expected_command)
shutup do
pkg_installer.install
pkg.install
end
Cask::FakeSystemCommand.system_calls[expected_command].must_equal 1
@ -25,13 +25,13 @@ describe Cask::PkgInstaller do
describe 'uninstall' do
it 'runs the specified uninstaller for the cask' do
pkg_installer = Cask::PkgInstaller.new(@cask, Cask::FakeSystemCommand)
pkg = Cask::Artifact::Pkg.new(@cask, Cask::FakeSystemCommand)
expected_command = "sudo '#{@cask.destination_path/'MyFancyPkg'/'FancyUninstaller.tool'}' '--please' 2>&1"
Cask::FakeSystemCommand.fake_response_for(expected_command)
shutup do
pkg_installer.uninstall
pkg.uninstall
end
Cask::FakeSystemCommand.system_calls[expected_command].must_equal 1
@ -39,7 +39,7 @@ describe Cask::PkgInstaller do
it 'can uninstall using pkgutil, launchctl, and file lists' do
cask = Cask.load('with-pkgutil-uninstall')
pkg_installer = Cask::PkgInstaller.new(cask, Cask::FakeSystemCommand)
pkg = Cask::Artifact::Pkg.new(cask, Cask::FakeSystemCommand)
Cask::FakeSystemCommand.fake_response_for(
%Q(pkgutil --pkgs="my.fancy.package.*" 2>&1),
@ -127,7 +127,7 @@ describe Cask::PkgInstaller do
# No assertions after call since all assertions are implicit from the interactions setup above.
# TODO: verify rmdir / rm commands (requires setting up actual file tree or faking out .exists?
shutup do
pkg_installer.uninstall
pkg.uninstall
end
end
end

View file

@ -23,19 +23,6 @@ describe Cask::DSL do
]
end
it "still lets you set content_length even though it is deprecated" do
OldContentLengthCask = Class.new(Cask)
begin
shutup do
OldContentLengthCask.class_eval do
content_length '12345'
end
end
rescue Exception => e
flunk("expected content_length to work, but got exception #{e}")
end
end
it "prevents the entire world from crashing when a cask includes an unknown method" do
UnexpectedMethodCask = Class.new(Cask)
begin
@ -49,17 +36,6 @@ describe Cask::DSL do
end
end
it "allows you to specify linkables in the old way, for backcompat" do
CaskWithOldSchoolLinkables = Class.new(Cask)
CaskWithOldSchoolLinkables.class_eval do
link :app, 'Foo.app'
link :app, 'Bar.app'
end
instance = CaskWithOldSchoolLinkables.new
Array(instance.linkables).sort.must_equal %w[Bar.app Foo.app]
end
it "allows you to specify linkables" do
CaskWithLinkables = Class.new(Cask)
CaskWithLinkables.class_eval do
@ -68,14 +44,14 @@ describe Cask::DSL do
end
instance = CaskWithLinkables.new
Array(instance.linkables).sort.must_equal %w[Bar.app Foo.app]
Array(instance.artifacts[:link]).sort.must_equal %w[Bar.app Foo.app]
end
it "allow linkables to be set to empty" do
CaskWithNoLinkables = Class.new(Cask)
instance = CaskWithNoLinkables.new
Array(instance.linkable_apps).must_equal %w[]
Array(instance.artifacts[:link]).must_equal %w[]
end
it "allows caveats to be specified via a method define" do
@ -106,6 +82,6 @@ describe Cask::DSL do
end
instance = CaskWithInstallables.new
Array(instance.installables).sort.must_equal %w[Bar.pkg Foo.pkg]
Array(instance.artifacts[:install]).sort.must_equal %w[Bar.pkg Foo.pkg]
end
end

View file

@ -1,31 +0,0 @@
require 'test_helper'
describe Cask::CLI::Linkapps do
before do
shutup do
caffeine = Cask.load('local-caffeine')
transmission = Cask.load('local-transmission')
Cask::Installer.new(caffeine).install
Cask::Installer.new(transmission).install
end
end
it "only links casks mentioned when arguments are provided" do
shutup do
Cask::CLI::Linkapps.run('local-transmission')
end
TestHelper.valid_alias?(Cask.appdir/"Transmission.app").must_equal true
TestHelper.valid_alias?(Cask.appdir/"Caffeine.app").wont_equal true
end
it "links all installed casks when no arguments supplied" do
shutup do
Cask::CLI::Linkapps.run
end
TestHelper.valid_alias?(Cask.appdir/"Transmission.app").must_equal true
TestHelper.valid_alias?(Cask.appdir/"Caffeine.app").must_equal true
end
end

View file

@ -19,9 +19,7 @@ describe Cask::CLI::Uninstall do
shutup do
Cask::Installer.new(caffeine).install
Cask::AppLinker.new(caffeine).link
Cask::Installer.new(transmission).install
Cask::AppLinker.new(transmission).link
end
caffeine.must_be :installed?

View file

@ -1,28 +0,0 @@
require 'test_helper'
describe Cask::CLI::Unlinkapps do
before do
shutup do
# use CLI so both casks start installed and linked
Cask::CLI::Install.run('local-caffeine', 'local-transmission')
end
end
it "only unlinks casks mentioned when arguments are provided" do
shutup do
Cask::CLI::Unlinkapps.run('local-transmission')
end
(Cask.appdir/"Transmission.app").wont_be :symlink?
(Cask.appdir/"Caffeine.app").must_be :symlink?
end
it "unlinks all installed casks when no arguments supplied" do
shutup do
Cask::CLI::Unlinkapps.run
end
(Cask.appdir/"Transmission.app").wont_be :symlink?
(Cask.appdir/"Caffeine.app").wont_be :symlink?
end
end

View file

@ -3,6 +3,6 @@ class WithInstallable < TestCask
homepage 'http://example.com/fancy-pkg'
version '1.2.3'
sha1 '8588bd8175a54b8e0a1310cc18e6567d520ab7c4'
install 'Fancy.pkg'
install 'MyFancyPkg/Fancy.pkg'
uninstall :script => 'MyFancyPkg/FancyUninstaller.tool', :args => %w[--please]
end

View file

@ -1,7 +1,11 @@
module Cask::CleanupHooks
def after_teardown
super
Cask.all.select(&:installed?).each { |c| Cask::Installer.new(c).uninstall }
Cask.all.select(&:installed?).each do |cask|
Cask::Installer.new(cask).tap do |installer|
installer.purge_files
end
end
end
end

View file

@ -72,6 +72,13 @@ class TestHelper
return false unless candidate.symlink?
candidate.readlink.exist?
end
def self.install_without_artifacts(cask)
Cask::Installer.new(cask).tap do |i|
shutup { i.download }
i.extract_container
end
end
end
require 'support/fake_fetcher'