diff --git a/Casks/arduino.rb b/Casks/arduino.rb index 1621b830bbc7..7756969c55a0 100644 --- a/Casks/arduino.rb +++ b/Casks/arduino.rb @@ -8,7 +8,7 @@ license :gpl app 'Arduino.app' - binary 'Arduino.app/Contents/Java/arduino-builder' + binary "#{appdir}/Arduino.app/Contents/Java/arduino-builder" caveats do depends_on_java diff --git a/Casks/atom.rb b/Casks/atom.rb index 2d1bff3f5086..602dbefb5b24 100644 --- a/Casks/atom.rb +++ b/Casks/atom.rb @@ -14,8 +14,8 @@ depends_on macos: '>= :mountain_lion' app 'Atom.app' - binary 'Atom.app/Contents/Resources/app/apm/node_modules/.bin/apm', target: 'apm' - binary 'Atom.app/Contents/Resources/app/atom.sh', target: 'atom' + binary "#{appdir}/Atom.app/Contents/Resources/app/apm/node_modules/.bin/apm", target: 'apm' + binary "#{appdir}/Atom.app/Contents/Resources/app/atom.sh", target: 'atom' postflight do suppress_move_to_applications diff --git a/Casks/calibre.rb b/Casks/calibre.rb index 1cf7e760ec46..4d3c14b6a4e0 100644 --- a/Casks/calibre.rb +++ b/Casks/calibre.rb @@ -15,26 +15,26 @@ license :gpl app 'calibre.app' - binary 'calibre.app/Contents/MacOS/calibre' - binary 'calibre.app/Contents/MacOS/calibre-complete' - binary 'calibre.app/Contents/MacOS/calibre-customize' - binary 'calibre.app/Contents/MacOS/calibre-debug' - binary 'calibre.app/Contents/MacOS/calibre-parallel' - binary 'calibre.app/Contents/MacOS/calibre-server' - binary 'calibre.app/Contents/MacOS/calibre-smtp' - binary 'calibre.app/Contents/MacOS/calibredb' - binary 'calibre.app/Contents/MacOS/ebook-convert' - binary 'calibre.app/Contents/MacOS/ebook-device' - binary 'calibre.app/Contents/MacOS/ebook-edit' - binary 'calibre.app/Contents/MacOS/ebook-meta' - binary 'calibre.app/Contents/MacOS/ebook-polish' - binary 'calibre.app/Contents/MacOS/ebook-viewer' - binary 'calibre.app/Contents/MacOS/fetch-ebook-metadata' - binary 'calibre.app/Contents/MacOS/lrf2lrs' - binary 'calibre.app/Contents/MacOS/lrfviewer' - binary 'calibre.app/Contents/MacOS/lrs2lrf' - binary 'calibre.app/Contents/MacOS/markdown-calibre' - binary 'calibre.app/Contents/MacOS/web2disk' + binary "#{appdir}/calibre.app/Contents/MacOS/calibre" + binary "#{appdir}/calibre.app/Contents/MacOS/calibre-complete" + binary "#{appdir}/calibre.app/Contents/MacOS/calibre-customize" + binary "#{appdir}/calibre.app/Contents/MacOS/calibre-debug" + binary "#{appdir}/calibre.app/Contents/MacOS/calibre-parallel" + binary "#{appdir}/calibre.app/Contents/MacOS/calibre-server" + binary "#{appdir}/calibre.app/Contents/MacOS/calibre-smtp" + binary "#{appdir}/calibre.app/Contents/MacOS/calibredb" + binary "#{appdir}/calibre.app/Contents/MacOS/ebook-convert" + binary "#{appdir}/calibre.app/Contents/MacOS/ebook-device" + binary "#{appdir}/calibre.app/Contents/MacOS/ebook-edit" + binary "#{appdir}/calibre.app/Contents/MacOS/ebook-meta" + binary "#{appdir}/calibre.app/Contents/MacOS/ebook-polish" + binary "#{appdir}/calibre.app/Contents/MacOS/ebook-viewer" + binary "#{appdir}/calibre.app/Contents/MacOS/fetch-ebook-metadata" + binary "#{appdir}/calibre.app/Contents/MacOS/lrf2lrs" + binary "#{appdir}/calibre.app/Contents/MacOS/lrfviewer" + binary "#{appdir}/calibre.app/Contents/MacOS/lrs2lrf" + binary "#{appdir}/calibre.app/Contents/MacOS/markdown-calibre" + binary "#{appdir}/calibre.app/Contents/MacOS/web2disk" zap delete: [ '~/Library/Preferences/net.kovidgoyal.calibre.plist', diff --git a/Casks/changes.rb b/Casks/changes.rb index aff76e5747ce..547f08fd3456 100644 --- a/Casks/changes.rb +++ b/Casks/changes.rb @@ -11,7 +11,7 @@ license :commercial app 'Changes.app' - binary 'Changes.app/Contents/Resources/chdiff' + binary "#{appdir}/Changes.app/Contents/Resources/chdiff" zap delete: [ '~/Library/Preferences/com.bitbq.Changes.plist', diff --git a/Casks/cmake.rb b/Casks/cmake.rb index 49be99e788a7..a723c7ca08d7 100644 --- a/Casks/cmake.rb +++ b/Casks/cmake.rb @@ -10,10 +10,10 @@ conflicts_with formula: 'cmake' app 'CMake.app' - binary 'CMake.app/Contents/bin/cmake' - binary 'CMake.app/Contents/bin/ccmake' - binary 'CMake.app/Contents/bin/cmakexbuild' - binary 'CMake.app/Contents/bin/cpack' - binary 'CMake.app/Contents/bin/ctest' - binary 'CMake.app/Contents/bin/cmake-gui' + binary "#{appdir}/CMake.app/Contents/bin/cmake" + binary "#{appdir}/CMake.app/Contents/bin/ccmake" + binary "#{appdir}/CMake.app/Contents/bin/cmakexbuild" + binary "#{appdir}/CMake.app/Contents/bin/cpack" + binary "#{appdir}/CMake.app/Contents/bin/ctest" + binary "#{appdir}/CMake.app/Contents/bin/cmake-gui" end diff --git a/Casks/cocoapods.rb b/Casks/cocoapods.rb index df6a68e04cf5..ae07bd03a830 100644 --- a/Casks/cocoapods.rb +++ b/Casks/cocoapods.rb @@ -13,7 +13,7 @@ container type: :tar app 'CocoaPods.app' - binary 'CocoaPods.app/Contents/Helpers/pod' + binary "#{appdir}/CocoaPods.app/Contents/Helpers/pod" postflight do # Because Homebrew-Cask symlinks the binstub directly, stop the app from asking the user to install the binstub. diff --git a/Casks/emacs.rb b/Casks/emacs.rb index dca380d1f3a3..e7df0d1c4dfd 100644 --- a/Casks/emacs.rb +++ b/Casks/emacs.rb @@ -8,9 +8,9 @@ license :oss app 'Emacs.app' - binary 'Emacs.app/Contents/MacOS/bin/emacsclient' - binary 'Emacs.app/Contents/MacOS/bin/ctags' - binary 'Emacs.app/Contents/MacOS/bin/grep-changelog' - binary 'Emacs.app/Contents/MacOS/bin/ebrowse' - binary 'Emacs.app/Contents/MacOS/bin/etags' + binary "#{appdir}/Emacs.app/Contents/MacOS/bin/emacsclient" + binary "#{appdir}/Emacs.app/Contents/MacOS/bin/ctags" + binary "#{appdir}/Emacs.app/Contents/MacOS/bin/grep-changelog" + binary "#{appdir}/Emacs.app/Contents/MacOS/bin/ebrowse" + binary "#{appdir}/Emacs.app/Contents/MacOS/bin/etags" end diff --git a/Casks/filebot.rb b/Casks/filebot.rb index f31a9e6f3bdb..081a87becfa7 100644 --- a/Casks/filebot.rb +++ b/Casks/filebot.rb @@ -9,7 +9,7 @@ license :gpl app 'FileBot.app' - binary 'FileBot.app/Contents/MacOS/filebot.sh', target: 'filebot' + binary "#{appdir}/FileBot.app/Contents/MacOS/filebot.sh", target: 'filebot' caveats do depends_on_java('8') diff --git a/Casks/genymotion.rb b/Casks/genymotion.rb index accc593c5522..cc7eb6abdfd8 100644 --- a/Casks/genymotion.rb +++ b/Casks/genymotion.rb @@ -11,7 +11,7 @@ app 'Genymotion.app' app 'Genymotion Shell.app' - binary 'Genymotion Shell.app/Contents/MacOS/genyshell' + binary "#{appdir}/Genymotion Shell.app/Contents/MacOS/genyshell" caveats do files_in_usr_local diff --git a/Casks/git-annex.rb b/Casks/git-annex.rb index ed2241535a6f..34feedfd0145 100644 --- a/Casks/git-annex.rb +++ b/Casks/git-annex.rb @@ -38,8 +38,8 @@ ] app 'git-annex.app' - binary 'git-annex.app/Contents/MacOS/git-annex' - binary 'git-annex.app/Contents/MacOS/git-annex-shell' + binary "#{appdir}/git-annex.app/Contents/MacOS/git-annex" + binary "#{appdir}/git-annex.app/Contents/MacOS/git-annex-shell" uninstall launchctl: 'com.branchable.git-annex.assistant' diff --git a/Casks/github-desktop.rb b/Casks/github-desktop.rb index ddaa63828582..e707e04ff1bb 100644 --- a/Casks/github-desktop.rb +++ b/Casks/github-desktop.rb @@ -10,7 +10,7 @@ license :gratis app 'GitHub Desktop.app' - binary 'GitHub Desktop.app/Contents/MacOS/github_cli', target: 'github' + binary "#{appdir}/GitHub Desktop.app/Contents/MacOS/github_cli", target: 'github' postflight do suppress_move_to_applications diff --git a/Casks/gitup.rb b/Casks/gitup.rb index 1cec4ed5186b..89b00ad82128 100644 --- a/Casks/gitup.rb +++ b/Casks/gitup.rb @@ -13,5 +13,5 @@ depends_on macos: '>= :mountain_lion' app 'GitUp.app' - binary 'GitUp.app/Contents/SharedSupport/gitup' + binary "#{appdir}/GitUp.app/Contents/SharedSupport/gitup" end diff --git a/Casks/gitx.rb b/Casks/gitx.rb index 10663768925a..30b9f34d9a1b 100644 --- a/Casks/gitx.rb +++ b/Casks/gitx.rb @@ -15,7 +15,7 @@ ] app 'GitX.app' - binary 'GitX.app/Contents/Resources/gitx' + binary "#{appdir}/GitX.app/Contents/Resources/gitx" zap delete: [ '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/nl.frim.gitx.sfl', diff --git a/Casks/hockey.rb b/Casks/hockey.rb index 8f2928c3b9b4..1c973fd5002d 100644 --- a/Casks/hockey.rb +++ b/Casks/hockey.rb @@ -10,7 +10,7 @@ license :unknown # TODO: change license and remove this comment; ':unknown' is a machine-generated placeholder app 'HockeyApp.app' - binary 'HockeyApp.app/Contents/Resources/puck' + binary "#{appdir}/HockeyApp.app/Contents/Resources/puck" postflight do suppress_move_to_applications diff --git a/Casks/hopper-disassembler.rb b/Casks/hopper-disassembler.rb index 46fb110b46f3..0aa9728922a7 100644 --- a/Casks/hopper-disassembler.rb +++ b/Casks/hopper-disassembler.rb @@ -13,7 +13,7 @@ depends_on macos: '>= :lion' app "Hopper Disassembler v#{version.major}.app" - binary "Hopper Disassembler v#{version.major}.app/Contents/MacOS/hopper" + binary "#{appdir}/Hopper Disassembler v#{version.major}.app/Contents/MacOS/hopper" zap delete: [ '~/Library/Application Support/Hopper', diff --git a/Casks/inkscape.rb b/Casks/inkscape.rb index c3ce20d77e69..44be933c67a8 100644 --- a/Casks/inkscape.rb +++ b/Casks/inkscape.rb @@ -11,7 +11,7 @@ depends_on x11: true app 'Inkscape.app' - binary 'Inkscape.app/Contents/Resources/bin/inkscape' + binary "#{appdir}/Inkscape.app/Contents/Resources/bin/inkscape" zap delete: '~/.inkscape-etc' end diff --git a/Casks/julia.rb b/Casks/julia.rb index 59490fcb015f..3b50cfd7a2e3 100644 --- a/Casks/julia.rb +++ b/Casks/julia.rb @@ -11,7 +11,7 @@ depends_on macos: '>= :lion' app "Julia-#{version}.app" - binary "Julia-#{version}.app/Contents/Resources/julia/bin/julia" + binary "#{appdir}/Julia-#{version}.app/Contents/Resources/julia/bin/julia" zap delete: '~/.julia' end diff --git a/Casks/kaleidoscope.rb b/Casks/kaleidoscope.rb index dcf9ba7847f5..b1471601566b 100644 --- a/Casks/kaleidoscope.rb +++ b/Casks/kaleidoscope.rb @@ -12,7 +12,7 @@ auto_updates true app 'Kaleidoscope.app' - binary 'Kaleidoscope.app/Contents/Resources/bin/ksdiff' + binary "#{appdir}/Kaleidoscope.app/Contents/Resources/bin/ksdiff" postflight do suppress_move_to_applications diff --git a/Casks/kdiff3.rb b/Casks/kdiff3.rb index 392fb4478b0b..757055c7bf61 100644 --- a/Casks/kdiff3.rb +++ b/Casks/kdiff3.rb @@ -9,7 +9,7 @@ license :gpl app 'kdiff3.app' - binary 'kdiff3.app/Contents/MacOS/kdiff3' + binary "#{appdir}/kdiff3.app/Contents/MacOS/kdiff3" zap delete: '~/.kdiff3rc' end diff --git a/Casks/kivy.rb b/Casks/kivy.rb index 9d2d79884570..a4c59519bebc 100644 --- a/Casks/kivy.rb +++ b/Casks/kivy.rb @@ -11,5 +11,5 @@ # Renamed as suggested by developer: https://kivy.org/docs/installation/installation-osx.html#installation-on-os-x app 'Kivy3.app', target: 'Kivy.app' - binary 'Kivy3.app/Contents/Resources/script', target: 'kivy' + binary "#{appdir}/Kivy3.app/Contents/Resources/script", target: 'kivy' end diff --git a/Casks/kod.rb b/Casks/kod.rb index 0c7815b7dbae..da2b0092243a 100644 --- a/Casks/kod.rb +++ b/Casks/kod.rb @@ -9,5 +9,5 @@ license :oss app 'Kod.app' - binary 'Kod.app/Contents/SharedSupport/kod' + binary "#{appdir}/Kod.app/Contents/SharedSupport/kod" end diff --git a/Casks/laullon-gitx.rb b/Casks/laullon-gitx.rb index 47983c4ecc05..ef8a4e628617 100644 --- a/Casks/laullon-gitx.rb +++ b/Casks/laullon-gitx.rb @@ -16,5 +16,5 @@ ] app 'GitX.app' - binary 'GitX.app/Contents/Resources/gitx' + binary "#{appdir}/GitX.app/Contents/Resources/gitx" end diff --git a/Casks/libreoffice.rb b/Casks/libreoffice.rb index 775850e7e835..b77d985425f0 100644 --- a/Casks/libreoffice.rb +++ b/Casks/libreoffice.rb @@ -17,18 +17,18 @@ key_id: 'c2839ecad9408fbe9531c3e9f434a1efafeeaea3' app 'LibreOffice.app' - binary 'LibreOffice.app/Contents/MacOS/gengal' - binary 'LibreOffice.app/Contents/MacOS/regmerge' - binary 'LibreOffice.app/Contents/MacOS/regview' - binary 'LibreOffice.app/Contents/MacOS/senddoc' - binary 'LibreOffice.app/Contents/MacOS/soffice' - binary 'LibreOffice.app/Contents/MacOS/ui-previewer' - binary 'LibreOffice.app/Contents/MacOS/uno' - binary 'LibreOffice.app/Contents/MacOS/unoinfo' - binary 'LibreOffice.app/Contents/MacOS/unopkg' - binary 'LibreOffice.app/Contents/MacOS/urelibs' - binary 'LibreOffice.app/Contents/MacOS/uri-encode' - binary 'LibreOffice.app/Contents/MacOS/xpdfimport' + binary "#{appdir}/LibreOffice.app/Contents/MacOS/gengal" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/regmerge" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/regview" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/senddoc" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/soffice" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/ui-previewer" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/uno" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/unoinfo" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/unopkg" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/urelibs" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/uri-encode" + binary "#{appdir}/LibreOffice.app/Contents/MacOS/xpdfimport" zap delete: [ '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/org.libreoffice.script.sfl', diff --git a/Casks/love.rb b/Casks/love.rb index 936448018b47..a2ad4cedc853 100644 --- a/Casks/love.rb +++ b/Casks/love.rb @@ -9,5 +9,5 @@ license :oss app 'love.app' - binary 'love.app/Contents/MacOS/love' + binary "#{appdir}/love.app/Contents/MacOS/love" end diff --git a/Casks/macdown.rb b/Casks/macdown.rb index 198e4d9408fc..c3e845ecc0f7 100644 --- a/Casks/macdown.rb +++ b/Casks/macdown.rb @@ -11,7 +11,7 @@ license :mit app 'MacDown.app' - binary 'MacDown.app/Contents/SharedSupport/bin/macdown' + binary "#{appdir}/MacDown.app/Contents/SharedSupport/bin/macdown" zap delete: ['~/Library/Preferences/com.uranusjr.macdown.plist', '~/Library/Application Support/MacDown'] diff --git a/Casks/mailmate.rb b/Casks/mailmate.rb index 08e952f9058e..24f39dd47a79 100644 --- a/Casks/mailmate.rb +++ b/Casks/mailmate.rb @@ -9,7 +9,7 @@ license :commercial app 'MailMate.app' - binary 'MailMate.app/Contents/Resources/emate' + binary "#{appdir}/MailMate.app/Contents/Resources/emate" caveats do files_in_usr_local diff --git a/Casks/praat.rb b/Casks/praat.rb index 31ea504a6f52..c1df55ef45fd 100644 --- a/Casks/praat.rb +++ b/Casks/praat.rb @@ -16,5 +16,5 @@ license :gpl app 'Praat.app' - binary 'Praat.app/Contents/MacOS/Praat', target: 'praat' + binary "#{appdir}/Praat.app/Contents/MacOS/Praat", target: 'praat' end diff --git a/Casks/rowanj-gitx.rb b/Casks/rowanj-gitx.rb index 6c1a3c3b4367..15714b92b57d 100644 --- a/Casks/rowanj-gitx.rb +++ b/Casks/rowanj-gitx.rb @@ -23,5 +23,5 @@ depends_on arch: :intel app 'GitX.app' - binary 'GitX.app/Contents/Resources/gitx' + binary "#{appdir}/GitX.app/Contents/Resources/gitx" end diff --git a/Casks/sage.rb b/Casks/sage.rb index 7e4a4e03fc62..32077ee3f556 100644 --- a/Casks/sage.rb +++ b/Casks/sage.rb @@ -25,10 +25,10 @@ if MacOS.release <= :yosemite app "Sage-#{version}.app" - binary "Sage-#{version}.app/Contents/Resources/sage/sage" + binary "#{appdir}/Sage-#{version}.app/Contents/Resources/sage/sage" else app "SageMath-#{version}.app" - binary "SageMath-#{version}.app/Contents/Resources/sage/sage" + binary "#{appdir}/SageMath-#{version}.app/Contents/Resources/sage/sage" end zap delete: [ diff --git a/Casks/skim.rb b/Casks/skim.rb index 049dfa025a0d..f6730730f699 100644 --- a/Casks/skim.rb +++ b/Casks/skim.rb @@ -10,9 +10,9 @@ license :bsd app 'Skim.app' - binary 'Skim.app/Contents/SharedSupport/displayline' - binary 'Skim.app/Contents/SharedSupport/skimnotes' - binary 'Skim.app/Contents/SharedSupport/skimpdf' + binary "#{appdir}/Skim.app/Contents/SharedSupport/displayline" + binary "#{appdir}/Skim.app/Contents/SharedSupport/skimnotes" + binary "#{appdir}/Skim.app/Contents/SharedSupport/skimpdf" zap delete: '~/Library/Preferences/net.sourceforge.skim-app.skim.plist' end diff --git a/Casks/smartgit.rb b/Casks/smartgit.rb index 86da3d81ac50..b66ff04958e7 100644 --- a/Casks/smartgit.rb +++ b/Casks/smartgit.rb @@ -8,7 +8,7 @@ license :commercial app 'SmartGit.app' - binary 'SmartGit.app/Contents/MacOS/SmartGit' + binary "#{appdir}/SmartGit.app/Contents/MacOS/SmartGit" caveats do files_in_usr_local diff --git a/Casks/smartsynchronize.rb b/Casks/smartsynchronize.rb index 3fc096555de1..03897eaba37d 100644 --- a/Casks/smartsynchronize.rb +++ b/Casks/smartsynchronize.rb @@ -10,7 +10,7 @@ depends_on macos: '>= :lion' app 'SmartSynchronize.app' - binary 'SmartSynchronize.app/Contents/MacOS/SmartSynchronize' + binary "#{appdir}/SmartSynchronize.app/Contents/MacOS/SmartSynchronize" caveats do files_in_usr_local diff --git a/Casks/sopcast.rb b/Casks/sopcast.rb index 58bbac195947..98bcc3b7e93d 100644 --- a/Casks/sopcast.rb +++ b/Casks/sopcast.rb @@ -8,7 +8,7 @@ license :gratis app 'SopCast.app' - binary 'SopCast.app/Contents/Resources/binaries/m32/sp-sc-auth' + binary "#{appdir}/SopCast.app/Contents/Resources/binaries/m32/sp-sc-auth" caveats do files_in_usr_local diff --git a/Casks/sourcetree.rb b/Casks/sourcetree.rb index 4fabe271179b..4effdeb9bc35 100644 --- a/Casks/sourcetree.rb +++ b/Casks/sourcetree.rb @@ -21,7 +21,7 @@ auto_updates true app 'SourceTree.app' - binary 'SourceTree.app/Contents/Resources/stree' + binary "#{appdir}/SourceTree.app/Contents/Resources/stree" postflight do suppress_move_to_applications diff --git a/Casks/sublime-text.rb b/Casks/sublime-text.rb index 31ebf7e6ff2b..a9c4b5eab959 100644 --- a/Casks/sublime-text.rb +++ b/Casks/sublime-text.rb @@ -11,7 +11,7 @@ license :closed app 'Sublime Text 2.app' - binary 'Sublime Text 2.app/Contents/SharedSupport/bin/subl' + binary "#{appdir}/Sublime Text 2.app/Contents/SharedSupport/bin/subl" zap delete: [ '~/Library/Application Support/Sublime Text 2', diff --git a/Casks/swi-prolog.rb b/Casks/swi-prolog.rb index c0d00388a575..3a1a556b282c 100644 --- a/Casks/swi-prolog.rb +++ b/Casks/swi-prolog.rb @@ -8,6 +8,6 @@ license :oss app 'SWI-Prolog.app' - binary 'SWI-Prolog.app/Contents/MacOS/swipl' - binary 'SWI-Prolog.app/Contents/MacOS/swipl-ld' + binary "#{appdir}/SWI-Prolog.app/Contents/MacOS/swipl" + binary "#{appdir}/SWI-Prolog.app/Contents/MacOS/swipl-ld" end diff --git a/Casks/textmate.rb b/Casks/textmate.rb index bc74f9d81d53..e56239b1054d 100644 --- a/Casks/textmate.rb +++ b/Casks/textmate.rb @@ -9,7 +9,7 @@ license :gpl app 'TextMate.app' - binary 'TextMate.app/Contents/Resources/mate' + binary "#{appdir}/TextMate.app/Contents/Resources/mate" zap delete: [ '~/Library/Application Support/Avian', diff --git a/Casks/textwrangler.rb b/Casks/textwrangler.rb index bd5a03daee92..a9e18f3c5ebf 100644 --- a/Casks/textwrangler.rb +++ b/Casks/textwrangler.rb @@ -20,7 +20,7 @@ depends_on macos: '>= :snow_leopard' app 'TextWrangler.app' - binary 'TextWrangler.app/Contents/Helpers/edit' - binary 'TextWrangler.app/Contents/Helpers/twdiff' - binary 'TextWrangler.app/Contents/Helpers/twfind' + binary "#{appdir}/TextWrangler.app/Contents/Helpers/edit" + binary "#{appdir}/TextWrangler.app/Contents/Helpers/twdiff" + binary "#{appdir}/TextWrangler.app/Contents/Helpers/twfind" end diff --git a/Casks/tower.rb b/Casks/tower.rb index 4bdbb22c9027..541dac4b5a13 100644 --- a/Casks/tower.rb +++ b/Casks/tower.rb @@ -11,7 +11,7 @@ license :commercial app 'Tower.app' - binary 'Tower.app/Contents/MacOS/gittower' + binary "#{appdir}/Tower.app/Contents/MacOS/gittower" zap delete: [ "~/Library/Application Support/com.fournova.Tower#{version.major}", diff --git a/Casks/vico.rb b/Casks/vico.rb index 71a8a789369a..db28665f5c5c 100644 --- a/Casks/vico.rb +++ b/Casks/vico.rb @@ -10,5 +10,5 @@ license :unknown # TODO: change license and remove this comment; ':unknown' is a machine-generated placeholder app 'Vico.app' - binary 'Vico.app/Contents/MacOS/vicotool', target: 'vico' + binary "#{appdir}/Vico.app/Contents/MacOS/vicotool", target: 'vico' end diff --git a/Casks/vimr.rb b/Casks/vimr.rb index 9de577dcfb88..c4e0023f7a13 100644 --- a/Casks/vimr.rb +++ b/Casks/vimr.rb @@ -11,5 +11,5 @@ license :gpl app 'VimR.app' - binary 'VimR.app/Contents/Resources/vimr' + binary "#{appdir}/VimR.app/Contents/Resources/vimr" end diff --git a/Casks/visual-studio-code.rb b/Casks/visual-studio-code.rb index 87b99381135b..14559cbe1eb9 100644 --- a/Casks/visual-studio-code.rb +++ b/Casks/visual-studio-code.rb @@ -12,7 +12,7 @@ auto_updates true app 'Visual Studio Code.app' - binary 'Visual Studio Code.app/Contents/Resources/app/bin/code' + binary "#{appdir}/Visual Studio Code.app/Contents/Resources/app/bin/code" zap delete: [ '~/Library/Application Support/Code', diff --git a/Casks/vmware-fusion.rb b/Casks/vmware-fusion.rb index 1ca97a161f88..d4654338d0c5 100644 --- a/Casks/vmware-fusion.rb +++ b/Casks/vmware-fusion.rb @@ -10,30 +10,30 @@ auto_updates true app 'VMware Fusion.app' - binary 'VMware Fusion.app/Contents/Library/vmnet-bridge' - binary 'VMware Fusion.app/Contents/Library/vmnet-cfgcli' - binary 'VMware Fusion.app/Contents/Library/vmnet-cli' - binary 'VMware Fusion.app/Contents/Library/vmnet-dhcpd' - binary 'VMware Fusion.app/Contents/Library/vmnet-natd' - binary 'VMware Fusion.app/Contents/Library/vmnet-netifup' - binary 'VMware Fusion.app/Contents/Library/vmnet-sniffer' - binary 'VMware Fusion.app/Contents/Library/vmrun' - binary 'VMware Fusion.app/Contents/Library/vmss2core' - binary 'VMware Fusion.app/Contents/Library/vmware-aewp' - binary 'VMware Fusion.app/Contents/Library/vmware-authd' - binary 'VMware Fusion.app/Contents/Library/vmware-cloneBootCamp' - binary 'VMware Fusion.app/Contents/Library/vmware-id' - binary 'VMware Fusion.app/Contents/Library/vmware-ntfs' - binary 'VMware Fusion.app/Contents/Library/vmware-rawdiskAuthTool' - binary 'VMware Fusion.app/Contents/Library/vmware-rawdiskCreator' - binary 'VMware Fusion.app/Contents/Library/vmware-remotemks' - binary 'VMware Fusion.app/Contents/Library/vmware-usbarbitrator' - binary 'VMware Fusion.app/Contents/Library/vmware-vdiskmanager' - binary 'VMware Fusion.app/Contents/Library/vmware-vmdkserver' - binary 'VMware Fusion.app/Contents/Library/vmware-vmx' - binary 'VMware Fusion.app/Contents/Library/vmware-vmx-debug' - binary 'VMware Fusion.app/Contents/Library/vmware-vmx-stats' - binary 'VMware Fusion.app/Contents/Library/VMware OVF Tool/ovftool' + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmnet-bridge" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmnet-cfgcli" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmnet-cli" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmnet-dhcpd" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmnet-natd" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmnet-netifup" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmnet-sniffer" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmrun" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmss2core" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-aewp" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-authd" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-cloneBootCamp" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-id" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-ntfs" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-rawdiskAuthTool" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-rawdiskCreator" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-remotemks" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-usbarbitrator" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-vdiskmanager" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-vmdkserver" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-vmx" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-vmx-debug" + binary "#{appdir}/VMware Fusion.app/Contents/Library/vmware-vmx-stats" + binary "#{appdir}/VMware Fusion.app/Contents/Library/VMware OVF Tool/ovftool" uninstall_preflight do set_ownership "#{staged_path}/VMware Fusion.app" diff --git a/README.md b/README.md index 63be950edfdd..cd980ade2c03 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ $ brew cask install google-chrome And there we have it. Google Chrome installed with a few quick commands: no clicking, no dragging, no dropping. ```bash -$ open ~/Applications/"Google Chrome.app" +$ open /Applications/"Google Chrome.app" ``` ## Learn More diff --git a/USAGE.md b/USAGE.md index 467e0c1c7e8b..78d547670dd7 100644 --- a/USAGE.md +++ b/USAGE.md @@ -53,7 +53,7 @@ Easy peasy: $ brew cask uninstall google-chrome ``` -This will both uninstall the Cask and remove symlinks which were created in `~/Applications`. +This will both uninstall the Cask and remove applications which were moved to `/Applications`. To uninstall all versions of a Cask, use `--force`: @@ -176,35 +176,34 @@ You can also modify the default installation locations used when issuing `brew c * `--caskroom=/my/path` determines where the actual applications will be located. Should be handled with care — setting it outside `/opt` or your home directory might mess up your system. Default is `/opt/homebrew-cask/Caskroom` -* `--appdir=/my/path` changes the path where the symlinks to the applications (above) -will be generated. This is commonly used to create the links in the _root_ Applications directory -instead of the _home_ Applications directory by specifying `--appdir=/Applications`. Default is `~/Applications`. -* `--prefpanedir=/my/path` changes the path for PreferencePane symlinks. +* `--appdir=/my/path` changes the path where the applications (above) +will be moved. Default is `/Applications`. +* `--prefpanedir=/my/path` changes the path for PreferencePanes. Default is `~/Library/PreferencePanes` -* `--qlplugindir=/my/path` changes the path for Quicklook Plugin symlinks. +* `--qlplugindir=/my/path` changes the path for Quicklook Plugins. Default is `~/Library/QuickLook` -* `--fontdir=/my/path` changes the path for Fonts symlinks. +* `--fontdir=/my/path` changes the path for Fonts. Default is `~/Library/Fonts` * `--binarydir=/my/path` changes the path for Binary symlinks. Default is `/usr/local/bin` -* `--input_methoddir=/my/path` changes the path for Input Methods symlinks. +* `--input_methoddir=/my/path` changes the path for Input Methods. Default is `~/Library/Input Methods` -* `--screen_saverdir=/my/path` changes the path for Screen Saver symlinks. +* `--screen_saverdir=/my/path` changes the path for Screen Savers. Default is `~/Library/Screen Savers` To make these settings persistent, you might want to add the following line to your `.bash_profile` or `.zshenv`: ```bash # Specify your defaults in this environment variable -export HOMEBREW_CASK_OPTS="--appdir=/Applications --caskroom=/etc/Caskroom" +export HOMEBREW_CASK_OPTS="--appdir=~/Applications --caskroom=/etc/Caskroom" ``` Note that you still can override the environment variable `HOMEBREW_CASK_OPTS` by _explicitly_ providing options in the command line: ```bash -# Will force the Chrome app to be linked to ~/Applications -# even though HOMEBREW_CASK_OPTS specified /Applications -$ brew cask install --appdir="~/Applications" google-chrome +# Will force the Chrome app to be linked to /Applications +# even though HOMEBREW_CASK_OPTS specified ~/Applications +$ brew cask install --appdir="/Applications" google-chrome ``` ## Advanced Searching diff --git a/doc/cask_language_reference/all_stanzas.md b/doc/cask_language_reference/all_stanzas.md index 4cea8f7a44de..4dceaaa0ddf2 100644 --- a/doc/cask_language_reference/all_stanzas.md +++ b/doc/cask_language_reference/all_stanzas.md @@ -19,7 +19,7 @@ Each Cask must declare one or more *artifacts* (i.e. something to install). | name | multiple occurrences allowed? | value | | ------------------ |------------------------------ | ----------- | -| `app` | yes | relative path to an `.app` that should be linked into the `~/Applications` folder on installation (see also [App Stanza Details](stanzas/app.md)) +| `app` | yes | relative path to an `.app` that should be moved into the `/Applications` folder on installation (see also [App Stanza Details](stanzas/app.md)) | `pkg` | yes | relative path to a `.pkg` file containing the distribution (see also [Pkg Stanza Details](stanzas/pkg.md)) | `binary` | yes | relative path to a Binary that should be linked into the `/usr/local/bin` folder on installation | `colorpicker` | yes | relative path to a ColorPicker plugin that should be linked into the `~/Library/ColorPickers` folder on installation @@ -33,7 +33,7 @@ Each Cask must declare one or more *artifacts* (i.e. something to install). | `audio_unit_plugin`| yes | relative path to an Audio Unit plugin that should be linked into the `~/Library/Audio/Components` folder on installation | `vst_plugin` | yes | relative path to a VST Plugin that should be linked into the `~/Library/Audio/VST` folder on installation | `vst3_plugin` | yes | relative path to a VST3 Plugin that should be linked into the `~/Library/Audio/VST3` folder on installation -| `suite` | yes | relative path to a containing directory that should be linked into the `~/Applications` folder on installation (see also [Suite Stanza Details](stanzas/suite.md)) +| `suite` | yes | relative path to a containing directory that should be linked into the `/Applications` folder on installation (see also [Suite Stanza Details](stanzas/suite.md)) | `artifact` | yes | relative path to an arbitrary path that should be symlinked on installation. Must provide an absolute path as a `target` (example [alcatraz.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/alcatraz.rb#L12)). This is only for unusual cases. The `app` stanza is strongly preferred when linking `.app` bundles. | `installer` | yes | describes an executable which must be run to complete the installation (see [Installer Stanza Details](stanzas/installer.md)) | `stage_only` | no | `true`. Assert that the Cask contains no activatable artifacts. diff --git a/doc/cask_language_reference/stanzas/app.md b/doc/cask_language_reference/stanzas/app.md index 5dbc71706834..aa17b475344d 100644 --- a/doc/cask_language_reference/stanzas/app.md +++ b/doc/cask_language_reference/stanzas/app.md @@ -1,18 +1,18 @@ # app -In the simple case of a string argument to `app`, a symlink is created in the target `~/Applications` directory using the same basename as the source file. For example: +In the simple case of a string argument to `app`, the source file is moved to the target `~/Applications` directory. For example: ```ruby app 'Alfred 2.app' ``` -causes the creation of this symlink: +moves the source to: ```bash ~/Applications/Alfred 2.app ``` -which points to a source file such as: +from a source file such as: ```bash /opt/homebrew-cask/Caskroom/alfred/2.8.2_431/Alfred 2.app @@ -20,7 +20,7 @@ which points to a source file such as: ## Renaming the Target -You can rename the target link which appears in your `~/Applications` directory by adding a `target:` key to `app`. Example (from [scala-ide.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/scala-ide.rb#L21)): +You can rename the target which appears in your `/Applications` directory by adding a `target:` key to `app`. Example (from [scala-ide.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/scala-ide.rb#L21)): ```ruby app 'eclipse/Eclipse.app', target: 'Scala IDE.app' diff --git a/doc/cask_language_reference/stanzas/suite.md b/doc/cask_language_reference/stanzas/suite.md index 0e4d2ed9c4fd..024b3393f53f 100644 --- a/doc/cask_language_reference/stanzas/suite.md +++ b/doc/cask_language_reference/stanzas/suite.md @@ -1,6 +1,6 @@ # suite -Some distributions provide a suite of multiple applications, or an application with required data, to be installed together in a subdirectory of `~/Applications`. +Some distributions provide a suite of multiple applications, or an application with required data, to be installed together in a subdirectory of `/Applications`. For these Casks, use the `suite` stanza to define the directory containing the application suite. Example (from [sketchup.rb](https://github.com/caskroom/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/sketchup.rb#L12)): diff --git a/doc/development/adding_a_cask.md b/doc/development/adding_a_cask.md index 5ff0ce244b8d..7626989b849e 100644 --- a/doc/development/adding_a_cask.md +++ b/doc/development/adding_a_cask.md @@ -98,7 +98,7 @@ Fill in the following stanzas for your Cask: | `name` | the full and proper name defined by the vendor, and any useful alternate names (see [Name Stanza Details](../cask_language_reference/stanzas/name.md)) | `homepage` | application homepage; used for the `brew cask home` command | `license` | a symbol identifying the license for the application. Valid category licenses include `:oss`, `:closed`, and `:unknown`. It is OK to leave as `:unknown`. (see [License Stanza Details](../cask_language_reference/stanzas/license.md)) -| `app` | relative path to an `.app` bundle that should be linked into the `~/Applications` folder on installation (see [App Stanza Details](../cask_language_reference/stanzas/app.md)) +| `app` | relative path to an `.app` bundle that should be moved into the `/Applications` folder on installation (see [App Stanza Details](../cask_language_reference/stanzas/app.md)) Other commonly-used stanzas are: diff --git a/doc/man_page/brew-cask.1.md b/doc/man_page/brew-cask.1.md index daebfc762705..a3b257e44b2f 100644 --- a/doc/man_page/brew-cask.1.md +++ b/doc/man_page/brew-cask.1.md @@ -149,7 +149,7 @@ in a future version. Give additional feedback during installation. * `--appdir=`: - Target location for Application links. The default value is `~/Applications`. + Target location for Application links. The default value is `/Applications`. * `--colorpickerdir=`: Target location for Color Picker links. The default value is `~/Library/Color Pickers`. diff --git a/lib/hbc.rb b/lib/hbc.rb index 97e69581d29d..7dee87b3a5fe 100644 --- a/lib/hbc.rb +++ b/lib/hbc.rb @@ -56,7 +56,7 @@ def self.init unless caskroom.exist? ohai "We need to make Caskroom for the first time at #{caskroom}" ohai "We'll set permissions properly so we won't need sudo in the future" - current_user = Etc.getpwuid(Process.euid).name + current_user = Hbc::Utils.current_user if caskroom.parent.writable? system '/bin/mkdir', '--', caskroom else diff --git a/lib/hbc/artifact.rb b/lib/hbc/artifact.rb index e99a3b6bad17..2b0d8f50cc16 100644 --- a/lib/hbc/artifact.rb +++ b/lib/hbc/artifact.rb @@ -4,6 +4,7 @@ module Hbc::Artifact; end require 'hbc/artifact/uninstall_base' require 'hbc/artifact/symlinked' require 'hbc/artifact/hardlinked' +require 'hbc/artifact/moved' require 'hbc/artifact/app' require 'hbc/artifact/artifact' # generic 'artifact' stanza diff --git a/lib/hbc/artifact/app.rb b/lib/hbc/artifact/app.rb index 9bb6a02371d2..0f557f3eec2e 100644 --- a/lib/hbc/artifact/app.rb +++ b/lib/hbc/artifact/app.rb @@ -1,2 +1,2 @@ -class Hbc::Artifact::App < Hbc::Artifact::Symlinked +class Hbc::Artifact::App < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/artifact.rb b/lib/hbc/artifact/artifact.rb index 47e7e2e1c4f0..468b9dae4143 100644 --- a/lib/hbc/artifact/artifact.rb +++ b/lib/hbc/artifact/artifact.rb @@ -1,4 +1,4 @@ -class Hbc::Artifact::Artifact < Hbc::Artifact::Symlinked +class Hbc::Artifact::Artifact < Hbc::Artifact::Moved def self.artifact_english_name 'Generic artifact' end diff --git a/lib/hbc/artifact/audio_unit_plugin.rb b/lib/hbc/artifact/audio_unit_plugin.rb index fd69116f1f2f..6e53aa441de2 100644 --- a/lib/hbc/artifact/audio_unit_plugin.rb +++ b/lib/hbc/artifact/audio_unit_plugin.rb @@ -1,3 +1,3 @@ -class Hbc::Artifact::AudioUnitPlugin < Hbc::Artifact::Symlinked +class Hbc::Artifact::AudioUnitPlugin < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/base.rb b/lib/hbc/artifact/base.rb index 6b43c57e0716..358bc640f6b8 100644 --- a/lib/hbc/artifact/base.rb +++ b/lib/hbc/artifact/base.rb @@ -24,6 +24,8 @@ def self.me?(cask) cask.artifacts[self.artifact_dsl_key].any? end + attr_reader :force + def zap_phase odebug "Nothing to do. The #{self.class.artifact_name} artifact has no zap phase." end @@ -76,8 +78,9 @@ def summary {} end - def initialize(cask, command=Hbc::SystemCommand) + def initialize(cask, options={}) @cask = cask - @command = command + @command = options.fetch(:command, Hbc::SystemCommand) + @force = options.fetch(:force, false) end end diff --git a/lib/hbc/artifact/colorpicker.rb b/lib/hbc/artifact/colorpicker.rb index 0f432e9c2106..724a8fd8a3c2 100644 --- a/lib/hbc/artifact/colorpicker.rb +++ b/lib/hbc/artifact/colorpicker.rb @@ -1,2 +1,2 @@ -class Hbc::Artifact::Colorpicker < Hbc::Artifact::Symlinked +class Hbc::Artifact::Colorpicker < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/input_method.rb b/lib/hbc/artifact/input_method.rb index f4e1185d7afd..20805e490996 100644 --- a/lib/hbc/artifact/input_method.rb +++ b/lib/hbc/artifact/input_method.rb @@ -1,2 +1,2 @@ -class Hbc::Artifact::InputMethod < Hbc::Artifact::Symlinked +class Hbc::Artifact::InputMethod < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/internet_plugin.rb b/lib/hbc/artifact/internet_plugin.rb index cc8f810aaf16..792ab71b209f 100644 --- a/lib/hbc/artifact/internet_plugin.rb +++ b/lib/hbc/artifact/internet_plugin.rb @@ -1,3 +1,3 @@ -class Hbc::Artifact::InternetPlugin < Hbc::Artifact::Symlinked +class Hbc::Artifact::InternetPlugin < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/moved.rb b/lib/hbc/artifact/moved.rb new file mode 100644 index 000000000000..d78a5642f1bd --- /dev/null +++ b/lib/hbc/artifact/moved.rb @@ -0,0 +1,117 @@ +class Hbc::Artifact::Moved < Hbc::Artifact::Base + ALT_NAME_ATTRIBUTE = 'com.apple.metadata:kMDItemAlternateNames' + + attr_reader :source, :target + + def english_name + self.class.artifact_english_name + end + + def summary + contents = @cask.artifacts[self.class.artifact_dsl_key].map do |artifact| + summarize_artifact(artifact) + end - [nil] + + { + :english_description => "#{english_name}s managed by brew-cask:", + :contents => contents + } + end + + def install_phase + each_artifact do |artifact| + load_specification(artifact) + next unless preflight_checks + delete if File.exist?(target) && force + move + end + end + + def uninstall_phase + each_artifact do |artifact| + load_specification(artifact) + next unless File.exist?(target) + delete + end + end + + private + + def each_artifact + # the sort is for predictability between Ruby versions + @cask.artifacts[self.class.artifact_dsl_key].sort.each do |artifact| + yield artifact + end + end + + def move + ohai "Moving #{english_name} '#{source.basename}' to '#{target}'" + target.dirname.mkpath + FileUtils.move(source, target) + end + + def load_specification(artifact_spec) + source_string, target_hash = artifact_spec + raise Hbc::CaskInvalidError if source_string.nil? + @source = @cask.staged_path.join(source_string) + if target_hash + raise Hbc::CaskInvalidError unless target_hash.respond_to?(:keys) + target_hash.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 + + def preflight_checks + if target.exist? + if force + ohai(warning_target_exists { |s| s << 'overwriting.' }) + else + ohai(warning_target_exists { |s| s << 'not moving.' }) + return false + end + end + unless source.exist? + message = "It seems the #{english_name} source is not there: '#{source}'" + raise Hbc::CaskError.new(message) + end + true + end + + def warning_target_exists + message_parts = [ + "It seems there is already #{ + self.class.artifact_english_article} #{english_name + } at '#{target}'" + ] + yield(message_parts) if block_given? + message_parts.join('; ') + end + + def delete + ohai "Removing #{english_name}: '#{target}'" + case + when Hbc::MacOS.undeletable?(target) + raise Hbc::CaskError.new( + "Cannot remove undeletable #{english_name}") + when force + Hbc::Utils.permissions_rmtree(target, command: @command) + else + target.rmtree + end + end + + def summarize_artifact(artifact_spec) + load_specification artifact_spec + printable_target = "'#{target}'" + printable_target.sub!(%r{^'#{ENV['HOME']}/*}, "~/'") + + unless target.exist? + warning = "Missing #{english_name}" + warning = "#{Tty.red.underline}#{warning}#{Tty.reset}: " + end + + "#{warning}#{printable_target}" + end +end diff --git a/lib/hbc/artifact/prefpane.rb b/lib/hbc/artifact/prefpane.rb index 9ad2527c35f3..b1b3241d843d 100644 --- a/lib/hbc/artifact/prefpane.rb +++ b/lib/hbc/artifact/prefpane.rb @@ -1,4 +1,4 @@ -class Hbc::Artifact::Prefpane < Hbc::Artifact::Symlinked +class Hbc::Artifact::Prefpane < Hbc::Artifact::Moved def self.artifact_english_name 'Preference Pane' end diff --git a/lib/hbc/artifact/qlplugin.rb b/lib/hbc/artifact/qlplugin.rb index a146184766d9..3500db44e68b 100644 --- a/lib/hbc/artifact/qlplugin.rb +++ b/lib/hbc/artifact/qlplugin.rb @@ -1,4 +1,4 @@ -class Hbc::Artifact::Qlplugin < Hbc::Artifact::Symlinked +class Hbc::Artifact::Qlplugin < Hbc::Artifact::Moved def self.artifact_english_name 'QuickLook Plugin' end diff --git a/lib/hbc/artifact/screen_saver.rb b/lib/hbc/artifact/screen_saver.rb index 0c37bc5c53eb..2d8d4ca06ee2 100644 --- a/lib/hbc/artifact/screen_saver.rb +++ b/lib/hbc/artifact/screen_saver.rb @@ -1,3 +1,3 @@ -class Hbc::Artifact::ScreenSaver < Hbc::Artifact::Symlinked +class Hbc::Artifact::ScreenSaver < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/service.rb b/lib/hbc/artifact/service.rb index 5240f5df5b57..41c6b245efd0 100644 --- a/lib/hbc/artifact/service.rb +++ b/lib/hbc/artifact/service.rb @@ -1,2 +1,2 @@ -class Hbc::Artifact::Service < Hbc::Artifact::Symlinked +class Hbc::Artifact::Service < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/suite.rb b/lib/hbc/artifact/suite.rb index 26959d705940..0d531abb6146 100644 --- a/lib/hbc/artifact/suite.rb +++ b/lib/hbc/artifact/suite.rb @@ -1,4 +1,4 @@ -class Hbc::Artifact::Suite < Hbc::Artifact::Symlinked +class Hbc::Artifact::Suite < Hbc::Artifact::Moved def self.artifact_english_name 'App Suite' end diff --git a/lib/hbc/artifact/uninstall_base.rb b/lib/hbc/artifact/uninstall_base.rb index b3bcf375f654..1b46eaae12e2 100644 --- a/lib/hbc/artifact/uninstall_base.rb +++ b/lib/hbc/artifact/uninstall_base.rb @@ -1,4 +1,3 @@ -require 'set' require 'pathname' class Hbc::Artifact::UninstallBase < Hbc::Artifact::Base @@ -8,138 +7,6 @@ class Hbc::Artifact::UninstallBase < Hbc::Artifact::Base PATH_ARG_SLICE_SIZE = 500 - # todo: There should be a way to specify a containing - # directory under which nothing can be deleted. - # - # This set should be merged with the SYSTEM_DIRS - # set found in lib/cask/pkg.rb. - UNDELETABLE_PATHS = Set.new [ - '~/', - '~/Applications', - '~/Desktop', - '~/Documents', - '~/Downloads', - '~/Mail', - '~/Movies', - '~/Music', - '~/Music/iTunes', - '~/Music/iTunes/iTunes Music', - '~/Music/iTunes/Album Artwork', - '~/News', - '~/Pictures', - '~/Pictures/Desktops', - '~/Pictures/Photo Booth', - '~/Pictures/iChat Icons', - '~/Pictures/iPhoto Library', - '~/Public', - '~/Sites', - '~/Library', - '~/Library/.localized', - '~/Library/Accessibility', - '~/Library/Accounts', - '~/Library/Address Book Plug-Ins', - '~/Library/Application Scripts', - '~/Library/Application Support', - '~/Library/Application Support/Apple', - '~/Library/Application Support/com.apple.AssistiveControl', - '~/Library/Application Support/com.apple.QuickLook', - '~/Library/Application Support/com.apple.TCC', - '~/Library/Assistants', - '~/Library/Audio', - '~/Library/Automator', - '~/Library/Autosave Information', - '~/Library/Caches', - '~/Library/Calendars', - '~/Library/ColorPickers', - '~/Library/ColorSync', - '~/Library/Colors', - '~/Library/Components', - '~/Library/Compositions', - '~/Library/Containers', - '~/Library/Contextual Menu Items', - '~/Library/Cookies', - '~/Library/DTDs', - '~/Library/Desktop Pictures', - '~/Library/Developer', - '~/Library/Dictionaries', - '~/Library/DirectoryServices', - '~/Library/Displays', - '~/Library/Documentation', - '~/Library/Extensions', - '~/Library/Favorites', - '~/Library/FileSync', - '~/Library/Filesystems', - '~/Library/Filters', - '~/Library/FontCollections', - '~/Library/Fonts', - '~/Library/Frameworks', - '~/Library/GameKit', - '~/Library/Graphics', - '~/Library/Group Containers', - '~/Library/Icons', - '~/Library/IdentityServices', - '~/Library/Image Capture', - '~/Library/Images', - '~/Library/Input Methods', - '~/Library/Internet Plug-Ins', - '~/Library/InternetAccounts', - '~/Library/iTunes', - '~/Library/KeyBindings', - '~/Library/Keyboard Layouts', - '~/Library/Keychains', - '~/Library/LaunchAgents', - '~/Library/LaunchDaemons', - '~/Library/LocationBundles', - '~/Library/LoginPlugins', - '~/Library/Logs', - '~/Library/Mail', - '~/Library/Mail Downloads', - '~/Library/Messages', - '~/Library/Metadata', - '~/Library/Mobile Documents', - '~/Library/MonitorPanels', - '~/Library/OpenDirectory', - '~/Library/PDF Services', - '~/Library/PhonePlugins', - '~/Library/Phones', - '~/Library/PreferencePanes', - '~/Library/Preferences', - '~/Library/Printers', - '~/Library/PrivateFrameworks', - '~/Library/PubSub', - '~/Library/QuickLook', - '~/Library/QuickTime', - '~/Library/Receipts', - '~/Library/Recent Servers', - '~/Library/Recents', - '~/Library/Safari', - '~/Library/Saved Application State', - '~/Library/Screen Savers', - '~/Library/ScreenReader', - '~/Library/ScriptingAdditions', - '~/Library/ScriptingDefinitions', - '~/Library/Scripts', - '~/Library/Security', - '~/Library/Services', - '~/Library/Sounds', - '~/Library/Speech', - '~/Library/Spelling', - '~/Library/Spotlight', - '~/Library/StartupItems', - '~/Library/StickiesDatabase', - '~/Library/Sync Services', - '~/Library/SyncServices', - '~/Library/SyncedPreferences', - '~/Library/TextEncodings', - '~/Library/User Pictures', - '~/Library/Video', - '~/Library/Voices', - '~/Library/WebKit', - '~/Library/WidgetResources', - '~/Library/Widgets', - '~/Library/Workflows', - ].map{|x| %r{\A~}.match(x) ? Pathname.new(x).expand_path : Pathname.new(x)} - ORDERED_DIRECTIVES = [ :early_script, :launchctl, @@ -175,7 +42,7 @@ def self.remove_relative_path_strings(action, path_strings) def self.remove_undeletable_path_strings(action, path_strings) undeletable = path_strings.map do |path_string| - path_string if UNDELETABLE_PATHS.include?(Pathname.new(path_string)) + path_string if Hbc::MacOS.undeletable?(Pathname.new(path_string)) end.compact undeletable.each do |path_string| opoo %Q{Skipping #{action} for undeletable path #{path_string}} diff --git a/lib/hbc/artifact/vst3_plugin.rb b/lib/hbc/artifact/vst3_plugin.rb index 0495781a897e..96f2516955d8 100644 --- a/lib/hbc/artifact/vst3_plugin.rb +++ b/lib/hbc/artifact/vst3_plugin.rb @@ -1,3 +1,3 @@ -class Hbc::Artifact::Vst3Plugin < Hbc::Artifact::Symlinked +class Hbc::Artifact::Vst3Plugin < Hbc::Artifact::Moved end diff --git a/lib/hbc/artifact/vst_plugin.rb b/lib/hbc/artifact/vst_plugin.rb index 14f32c98a3b6..a13a33c9a563 100644 --- a/lib/hbc/artifact/vst_plugin.rb +++ b/lib/hbc/artifact/vst_plugin.rb @@ -1,3 +1,3 @@ -class Hbc::Artifact::VstPlugin < Hbc::Artifact::Symlinked +class Hbc::Artifact::VstPlugin < Hbc::Artifact::Moved end diff --git a/lib/hbc/cli/fetch.rb b/lib/hbc/cli/fetch.rb index d64552ef7f02..8a46f9d7dd5b 100644 --- a/lib/hbc/cli/fetch.rb +++ b/lib/hbc/cli/fetch.rb @@ -7,7 +7,7 @@ def self.run(*args) cask_tokens.each do |cask_token| ohai "Downloading external files for Cask #{cask_token}" cask = Hbc.load(cask_token) - downloaded_path = Hbc::Download.new(cask, force).perform + downloaded_path = Hbc::Download.new(cask, force: force).perform Hbc::Verify.all(cask, downloaded_path) ohai "Success! Downloaded to -> #{downloaded_path}" end diff --git a/lib/hbc/cli/install.rb b/lib/hbc/cli/install.rb index b54494e706ec..9428bf39ded7 100644 --- a/lib/hbc/cli/install.rb +++ b/lib/hbc/cli/install.rb @@ -17,7 +17,7 @@ def self.install_casks(cask_tokens, force) cask_tokens.each do |cask_token| begin cask = Hbc.load(cask_token) - Hbc::Installer.new(cask).install(force) + Hbc::Installer.new(cask, force: force).install count += 1 rescue Hbc::CaskAlreadyInstalledError => e opoo e.message diff --git a/lib/hbc/cli/uninstall.rb b/lib/hbc/cli/uninstall.rb index bef08b2ad72b..6f0523a86937 100644 --- a/lib/hbc/cli/uninstall.rb +++ b/lib/hbc/cli/uninstall.rb @@ -6,8 +6,10 @@ def self.run(*args) cask_tokens.each do |cask_token| odebug "Uninstalling Cask #{cask_token}" cask = Hbc.load(cask_token) - raise Hbc::CaskNotInstalledError.new(cask) unless cask.installed? or force - Hbc::Installer.new(cask).uninstall(force) + unless cask.installed? || force + raise Hbc::CaskNotInstalledError.new(cask) + end + Hbc::Installer.new(cask, force: force).uninstall end end diff --git a/lib/hbc/download.rb b/lib/hbc/download.rb index 7a618a50e828..1769f268cec2 100644 --- a/lib/hbc/download.rb +++ b/lib/hbc/download.rb @@ -4,9 +4,9 @@ class Hbc::Download attr_reader :cask - def initialize(cask, force=false) + def initialize(cask, options={}) @cask = cask - @force = force + @force = options.fetch(:force, false) end def perform diff --git a/lib/hbc/dsl.rb b/lib/hbc/dsl.rb index 0e847eba2e3b..06ac1330fcf0 100644 --- a/lib/hbc/dsl.rb +++ b/lib/hbc/dsl.rb @@ -69,6 +69,7 @@ class Hbc::DSL :staged_path, :url, :version, + :appdir, *ORDINARY_ARTIFACT_TYPES, *ACTIVATABLE_ARTIFACT_TYPES, *SPECIAL_ARTIFACT_TYPES, @@ -280,6 +281,10 @@ def installer(*args) end end + def appdir + Hbc.appdir.sub(/\/$/, "") + end + SPECIAL_ARTIFACT_TYPES.each do |type| define_method(type) do |*args| artifacts[type].merge(args) diff --git a/lib/hbc/dsl/postflight.rb b/lib/hbc/dsl/postflight.rb index 3951da5cf478..97a54d59a0c4 100644 --- a/lib/hbc/dsl/postflight.rb +++ b/lib/hbc/dsl/postflight.rb @@ -4,17 +4,7 @@ class Hbc::DSL::Postflight < Hbc::DSL::Base include Hbc::Staged def suppress_move_to_applications(options = {}) - permitted_keys = [:key] - unknown_keys = options.keys - permitted_keys - unless unknown_keys.empty? - opoo %Q{Unknown arguments to suppress_move_to_applications -- #{unknown_keys.inspect} (ignored). Running "brew update; brew cleanup; brew cask cleanup" will likely fix it.} - end - key = options[:key] || 'moveToApplicationsFolderAlertSuppress' - begin - @command.run!('/usr/bin/defaults', :args => ['write', bundle_identifier, key, '-bool', 'true']) - rescue StandardError => e - raise Hbc::CaskError.new("#{@cask.token}: 'suppress_move_to_applications' failed with: #{e}") - end + # TODO: Remove from all casks because it is no longer needed end def method_missing(method, *args) diff --git a/lib/hbc/installer.rb b/lib/hbc/installer.rb index 38d6343abd03..7a46a57a3a83 100644 --- a/lib/hbc/installer.rb +++ b/lib/hbc/installer.rb @@ -14,11 +14,15 @@ class Hbc::Installer include Hbc::Staged include Hbc::Verify + attr_reader :force, :skip_cask_deps + PERSISTENT_METADATA_SUBDIRS = [ 'gpg' ] - def initialize(cask, command=Hbc::SystemCommand) + def initialize(cask, options={}) @cask = cask - @command = command + @command = options.fetch(:command, Hbc::SystemCommand) + @force = options.fetch(:force, false) + @skip_cask_deps = options.fetch(:skip_cask_deps, false) end def self.print_caveats(cask) @@ -50,7 +54,7 @@ def self.capture_output(&block) output end - def install(force=false, skip_cask_deps=false) + def install odebug "Hbc::Installer.install" if @cask.installed? && @cask.auto_updates && !force @@ -64,12 +68,12 @@ def install(force=false, skip_cask_deps=false) print_caveats begin - satisfy_dependencies(skip_cask_deps) + satisfy_dependencies download verify extract_primary_container install_artifacts - save_caskfile force + save_caskfile enable_accessibility_access rescue StandardError => e purge_versioned_files @@ -90,7 +94,7 @@ def summary def download odebug "Downloading" - download = Hbc::Download.new(@cask) + download = Hbc::Download.new(@cask, force: false) @downloaded_path = download.perform odebug "Downloaded to -> #{@downloaded_path}" @downloaded_path @@ -121,14 +125,15 @@ def install_artifacts odebug "#{artifacts.length} artifact/s defined", artifacts artifacts.each do |artifact| odebug "Installing artifact of class #{artifact}" - artifact.new(@cask, @command).install_phase + options = { command: @command, force: force } + artifact.new(@cask, options).install_phase end end # todo move dependencies to a separate class # dependencies should also apply for "brew cask stage" # override dependencies with --force or perhaps --force-deps - def satisfy_dependencies(skip_cask_deps=false) + def satisfy_dependencies if @cask.depends_on ohai 'Satisfying dependencies' macos_dependencies @@ -205,7 +210,8 @@ def cask_dependencies if dep.installed? puts "already installed" else - Hbc::Installer.new(dep).install(false, true) + Hbc::Installer.new(dep, + force: false, skip_cask_deps: true).install puts "done" end end @@ -258,7 +264,7 @@ def disable_accessibility_access end end - def save_caskfile(force=false) + def save_caskfile timestamp = :now create = true savedir = @cask.metadata_subdir('Casks', timestamp, create) @@ -274,7 +280,7 @@ def save_caskfile(force=false) FileUtils.copy(@cask.sourcefile_path, savedir) if @cask.sourcefile_path end - def uninstall(force=false) + def uninstall odebug "Hbc::Installer.uninstall" disable_accessibility_access uninstall_artifacts @@ -288,7 +294,8 @@ def uninstall_artifacts odebug "#{artifacts.length} artifact/s defined", artifacts artifacts.each do |artifact| odebug "Un-installing artifact of class #{artifact}" - artifact.new(@cask, @command).uninstall_phase + options = { command: @command, force: force } + artifact.new(@cask, options).uninstall_phase end end @@ -305,41 +312,8 @@ def zap purge_caskroom_path end - # this feels like a class method, but uses @command def permissions_rmtree(path) - if path.respond_to?(:rmtree) and path.exist? - tried_permissions = false - tried_ownership = false - begin - path.rmtree - rescue StandardError => e - # in case of permissions problems - unless tried_permissions - # todo Better handling for the case where path is a symlink. - # The -h and -R flags cannot be combined, and behavior is - # dependent on whether the file argument has a trailing - # slash. This should do the right thing, but is fragile. - @command.run!('/usr/bin/chflags', :args => ['-R', '--', '000', path]) - @command.run!('/bin/chmod', :args => ['-R', '--', 'u+rwx', path]) - @command.run!('/bin/chmod', :args => ['-R', '-N', path]) - tried_permissions = true - retry # rmtree - end - unless tried_ownership - # in case of ownership problems - # todo Further examine files to see if ownership is the problem - # before using sudo+chown - ohai "Using sudo to gain ownership of path '#{path}'" - current_user = Etc.getpwuid(Process.euid).name - @command.run('/usr/sbin/chown', :args => ['-R', '--', current_user, path], - :sudo => true) - tried_ownership = true - # retry chflags/chmod after chown - tried_permissions = false - retry # rmtree - end - end - end + Hbc::Utils.permissions_rmtree(path, command: @command) end def purge_versioned_files diff --git a/lib/hbc/locations.rb b/lib/hbc/locations.rb index aeb704ca0b80..9734af76bcab 100644 --- a/lib/hbc/locations.rb +++ b/lib/hbc/locations.rb @@ -13,7 +13,7 @@ def caskroom=(caskroom) end def appdir - @appdir ||= Pathname.new('~/Applications').expand_path + @appdir ||= Pathname.new('/Applications').expand_path end def appdir=(_appdir) diff --git a/lib/hbc/macos.rb b/lib/hbc/macos.rb index bd564065df01..0ac3e01930ef 100644 --- a/lib/hbc/macos.rb +++ b/lib/hbc/macos.rb @@ -1,10 +1,377 @@ # originally from Homebrew +require 'set' + require 'hbc/macos/release' module Hbc::MacOS extend self + SYSTEM_DIRS = [ + '/', + '/Applications', + '/Applications/Utilities', + '/Incompatible Software', + '/Library', + '/Library/Application Support', + '/Library/Audio', + '/Library/Caches', + '/Library/ColorPickers', + '/Library/ColorSync', + '/Library/Components', + '/Library/Compositions', + '/Library/Contextual Menu Items', + '/Library/CoreMediaIO', + '/Library/Desktop Pictures', + '/Library/Developer', + '/Library/Dictionaries', + '/Library/DirectoryServices', + '/Library/Documentation', + '/Library/Extensions', + '/Library/Filesystems', + '/Library/Fonts', + '/Library/Frameworks', + '/Library/Graphics', + '/Library/Image Capture', + '/Library/Input Methods', + '/Library/Internet Plug-Ins', + '/Library/Java', + '/Library/Keyboard Layouts', + '/Library/Keychains', + '/Library/LaunchAgents', + '/Library/LaunchDaemons', + '/Library/Logs', + '/Library/Messages', + '/Library/Modem Scripts', + '/Library/OpenDirectory', + '/Library/PDF Services', + '/Library/Perl', + '/Library/PreferencePanes', + '/Library/Preferences', + '/Library/Printers', + '/Library/PrivilegedHelperTools', + '/Library/Python', + '/Library/QuickLook', + '/Library/QuickTime', + '/Library/Receipts', + '/Library/Ruby', + '/Library/Sandbox', + '/Library/Screen Savers', + '/Library/ScriptingAdditions', + '/Library/Scripts', + '/Library/Security', + '/Library/Speech', + '/Library/Spelling', + '/Library/Spotlight', + '/Library/StartupItems', + '/Library/SystemProfiler', + '/Library/Updates', + '/Library/User Pictures', + '/Library/Video', + '/Library/WebServer', + '/Library/Widgets', + '/Library/iTunes', + '/Network', + '/System', + '/System/Library', + '/System/Library/Accessibility', + '/System/Library/Accounts', + '/System/Library/Address Book Plug-Ins', + '/System/Library/Assistant', + '/System/Library/Automator', + '/System/Library/BridgeSupport', + '/System/Library/Caches', + '/System/Library/ColorPickers', + '/System/Library/ColorSync', + '/System/Library/Colors', + '/System/Library/Components', + '/System/Library/Compositions', + '/System/Library/CoreServices', + '/System/Library/DTDs', + '/System/Library/DirectoryServices', + '/System/Library/Displays', + '/System/Library/Extensions', + '/System/Library/Filesystems', + '/System/Library/Filters', + '/System/Library/Fonts', + '/System/Library/Frameworks', + '/System/Library/Graphics', + '/System/Library/IdentityServices', + '/System/Library/Image Capture', + '/System/Library/Input Methods', + '/System/Library/InternetAccounts', + '/System/Library/Java', + '/System/Library/KerberosPlugins', + '/System/Library/Keyboard Layouts', + '/System/Library/Keychains', + '/System/Library/LaunchAgents', + '/System/Library/LaunchDaemons', + '/System/Library/LinguisticData', + '/System/Library/LocationBundles', + '/System/Library/LoginPlugins', + '/System/Library/Messages', + '/System/Library/Metadata', + '/System/Library/MonitorPanels', + '/System/Library/OpenDirectory', + '/System/Library/OpenSSL', + '/System/Library/Password Server Filters', + '/System/Library/PerformanceMetrics', + '/System/Library/Perl', + '/System/Library/PreferencePanes', + '/System/Library/Printers', + '/System/Library/PrivateFrameworks', + '/System/Library/QuickLook', + '/System/Library/QuickTime', + '/System/Library/QuickTimeJava', + '/System/Library/Recents', + '/System/Library/SDKSettingsPlist', + '/System/Library/Sandbox', + '/System/Library/Screen Savers', + '/System/Library/ScreenReader', + '/System/Library/ScriptingAdditions', + '/System/Library/ScriptingDefinitions', + '/System/Library/Security', + '/System/Library/Services', + '/System/Library/Sounds', + '/System/Library/Speech', + '/System/Library/Spelling', + '/System/Library/Spotlight', + '/System/Library/StartupItems', + '/System/Library/SyncServices', + '/System/Library/SystemConfiguration', + '/System/Library/SystemProfiler', + '/System/Library/Tcl', + '/System/Library/TextEncodings', + '/System/Library/User Template', + '/System/Library/UserEventPlugins', + '/System/Library/Video', + '/System/Library/WidgetResources', + '/User Information', + '/Users', + '/Volumes', + '/bin', + '/boot', + '/cores', + '/dev', + '/etc', + '/etc/X11', + '/etc/opt', + '/etc/sgml', + '/etc/xml', + '/home', + '/libexec', + '/lost+found', + '/media', + '/mnt', + '/net', + '/opt', + '/private', + '/private/etc', + '/private/tftpboot', + '/private/tmp', + '/private/var', + '/proc', + '/root', + '/sbin', + '/srv', + '/tmp', + '/usr', + '/usr/X11R6', + '/usr/bin', + '/usr/etc', + '/usr/include', + '/usr/lib', + '/usr/libexec', + '/usr/local', + '/usr/local/Cellar', + '/usr/local/Frameworks', + '/usr/local/Library', + '/usr/local/bin', + '/usr/local/etc', + '/usr/local/include', + '/usr/local/lib', + '/usr/local/libexec', + '/usr/local/opt', + '/usr/local/share', + '/usr/local/share/man', + '/usr/local/share/man/man1', + '/usr/local/share/man/man2', + '/usr/local/share/man/man3', + '/usr/local/share/man/man4', + '/usr/local/share/man/man5', + '/usr/local/share/man/man6', + '/usr/local/share/man/man7', + '/usr/local/share/man/man8', + '/usr/local/share/man/man9', + '/usr/local/share/man/mann', + '/usr/local/var', + '/usr/local/var/lib', + '/usr/local/var/lock', + '/usr/local/var/run', + '/usr/sbin', + '/usr/share', + '/usr/share/man', + '/usr/share/man/man1', + '/usr/share/man/man2', + '/usr/share/man/man3', + '/usr/share/man/man4', + '/usr/share/man/man5', + '/usr/share/man/man6', + '/usr/share/man/man7', + '/usr/share/man/man8', + '/usr/share/man/man9', + '/usr/share/man/mann', + '/usr/src', + '/var', + '/var/cache', + '/var/lib', + '/var/lock', + '/var/log', + '/var/mail', + '/var/run', + '/var/spool', + '/var/spool/mail', + '/var/tmp', + ].map { |x| Pathname.new(x) }.freeze + + # todo: There should be a way to specify a containing + # directory under which nothing can be deleted. + UNDELETABLE_DIRS = Set.new [ + '~/', + '~/Applications', + '~/Desktop', + '~/Documents', + '~/Downloads', + '~/Mail', + '~/Movies', + '~/Music', + '~/Music/iTunes', + '~/Music/iTunes/iTunes Music', + '~/Music/iTunes/Album Artwork', + '~/News', + '~/Pictures', + '~/Pictures/Desktops', + '~/Pictures/Photo Booth', + '~/Pictures/iChat Icons', + '~/Pictures/iPhoto Library', + '~/Public', + '~/Sites', + '~/Library', + '~/Library/.localized', + '~/Library/Accessibility', + '~/Library/Accounts', + '~/Library/Address Book Plug-Ins', + '~/Library/Application Scripts', + '~/Library/Application Support', + '~/Library/Application Support/Apple', + '~/Library/Application Support/com.apple.AssistiveControl', + '~/Library/Application Support/com.apple.QuickLook', + '~/Library/Application Support/com.apple.TCC', + '~/Library/Assistants', + '~/Library/Audio', + '~/Library/Automator', + '~/Library/Autosave Information', + '~/Library/Caches', + '~/Library/Calendars', + '~/Library/ColorPickers', + '~/Library/ColorSync', + '~/Library/Colors', + '~/Library/Components', + '~/Library/Compositions', + '~/Library/Containers', + '~/Library/Contextual Menu Items', + '~/Library/Cookies', + '~/Library/DTDs', + '~/Library/Desktop Pictures', + '~/Library/Developer', + '~/Library/Dictionaries', + '~/Library/DirectoryServices', + '~/Library/Displays', + '~/Library/Documentation', + '~/Library/Extensions', + '~/Library/Favorites', + '~/Library/FileSync', + '~/Library/Filesystems', + '~/Library/Filters', + '~/Library/FontCollections', + '~/Library/Fonts', + '~/Library/Frameworks', + '~/Library/GameKit', + '~/Library/Graphics', + '~/Library/Group Containers', + '~/Library/Icons', + '~/Library/IdentityServices', + '~/Library/Image Capture', + '~/Library/Images', + '~/Library/Input Methods', + '~/Library/Internet Plug-Ins', + '~/Library/InternetAccounts', + '~/Library/iTunes', + '~/Library/KeyBindings', + '~/Library/Keyboard Layouts', + '~/Library/Keychains', + '~/Library/LaunchAgents', + '~/Library/LaunchDaemons', + '~/Library/LocationBundles', + '~/Library/LoginPlugins', + '~/Library/Logs', + '~/Library/Mail', + '~/Library/Mail Downloads', + '~/Library/Messages', + '~/Library/Metadata', + '~/Library/Mobile Documents', + '~/Library/MonitorPanels', + '~/Library/OpenDirectory', + '~/Library/PDF Services', + '~/Library/PhonePlugins', + '~/Library/Phones', + '~/Library/PreferencePanes', + '~/Library/Preferences', + '~/Library/Printers', + '~/Library/PrivateFrameworks', + '~/Library/PubSub', + '~/Library/QuickLook', + '~/Library/QuickTime', + '~/Library/Receipts', + '~/Library/Recent Servers', + '~/Library/Recents', + '~/Library/Safari', + '~/Library/Saved Application State', + '~/Library/Screen Savers', + '~/Library/ScreenReader', + '~/Library/ScriptingAdditions', + '~/Library/ScriptingDefinitions', + '~/Library/Scripts', + '~/Library/Security', + '~/Library/Services', + '~/Library/Sounds', + '~/Library/Speech', + '~/Library/Spelling', + '~/Library/Spotlight', + '~/Library/StartupItems', + '~/Library/StickiesDatabase', + '~/Library/Sync Services', + '~/Library/SyncServices', + '~/Library/SyncedPreferences', + '~/Library/TextEncodings', + '~/Library/User Pictures', + '~/Library/Video', + '~/Library/Voices', + '~/Library/WebKit', + '~/Library/WidgetResources', + '~/Library/Widgets', + '~/Library/Workflows', + ].map { |x| %r{\A~}.match(x) ? + Pathname.new(x).expand_path + : Pathname.new(x) + } + .concat(SYSTEM_DIRS) + .freeze + + def undeletable?(dir) + UNDELETABLE_DIRS.any? { |u| File.identical?(u, dir) } + end + # These Comparable instances can be compared to numerics, strings, or symbols def release_with_patchlevel @@release_with_patchlevel ||= diff --git a/lib/hbc/pkg.rb b/lib/hbc/pkg.rb index 3e7805bd85c6..5934ccee976a 100644 --- a/lib/hbc/pkg.rb +++ b/lib/hbc/pkg.rb @@ -1,231 +1,4 @@ class Hbc::Pkg - SYSTEM_DIRS = [ - '/', - '/Applications', - '/Applications/Utilities', - '/Incompatible Software', - '/Library', - '/Library/Application Support', - '/Library/Audio', - '/Library/Caches', - '/Library/ColorPickers', - '/Library/ColorSync', - '/Library/Components', - '/Library/Compositions', - '/Library/Contextual Menu Items', - '/Library/CoreMediaIO', - '/Library/Desktop Pictures', - '/Library/Developer', - '/Library/Dictionaries', - '/Library/DirectoryServices', - '/Library/Documentation', - '/Library/Extensions', - '/Library/Filesystems', - '/Library/Fonts', - '/Library/Frameworks', - '/Library/Graphics', - '/Library/Image Capture', - '/Library/Input Methods', - '/Library/Internet Plug-Ins', - '/Library/Java', - '/Library/Keyboard Layouts', - '/Library/Keychains', - '/Library/LaunchAgents', - '/Library/LaunchDaemons', - '/Library/Logs', - '/Library/Messages', - '/Library/Modem Scripts', - '/Library/OpenDirectory', - '/Library/PDF Services', - '/Library/Perl', - '/Library/PreferencePanes', - '/Library/Preferences', - '/Library/Printers', - '/Library/PrivilegedHelperTools', - '/Library/Python', - '/Library/QuickLook', - '/Library/QuickTime', - '/Library/Receipts', - '/Library/Ruby', - '/Library/Sandbox', - '/Library/Screen Savers', - '/Library/ScriptingAdditions', - '/Library/Scripts', - '/Library/Security', - '/Library/Speech', - '/Library/Spelling', - '/Library/Spotlight', - '/Library/StartupItems', - '/Library/SystemProfiler', - '/Library/Updates', - '/Library/User Pictures', - '/Library/Video', - '/Library/WebServer', - '/Library/Widgets', - '/Library/iTunes', - '/Network', - '/System', - '/System/Library', - '/System/Library/Accessibility', - '/System/Library/Accounts', - '/System/Library/Address Book Plug-Ins', - '/System/Library/Assistant', - '/System/Library/Automator', - '/System/Library/BridgeSupport', - '/System/Library/Caches', - '/System/Library/ColorPickers', - '/System/Library/ColorSync', - '/System/Library/Colors', - '/System/Library/Components', - '/System/Library/Compositions', - '/System/Library/CoreServices', - '/System/Library/DTDs', - '/System/Library/DirectoryServices', - '/System/Library/Displays', - '/System/Library/Extensions', - '/System/Library/Filesystems', - '/System/Library/Filters', - '/System/Library/Fonts', - '/System/Library/Frameworks', - '/System/Library/Graphics', - '/System/Library/IdentityServices', - '/System/Library/Image Capture', - '/System/Library/Input Methods', - '/System/Library/InternetAccounts', - '/System/Library/Java', - '/System/Library/KerberosPlugins', - '/System/Library/Keyboard Layouts', - '/System/Library/Keychains', - '/System/Library/LaunchAgents', - '/System/Library/LaunchDaemons', - '/System/Library/LinguisticData', - '/System/Library/LocationBundles', - '/System/Library/LoginPlugins', - '/System/Library/Messages', - '/System/Library/Metadata', - '/System/Library/MonitorPanels', - '/System/Library/OpenDirectory', - '/System/Library/OpenSSL', - '/System/Library/Password Server Filters', - '/System/Library/PerformanceMetrics', - '/System/Library/Perl', - '/System/Library/PreferencePanes', - '/System/Library/Printers', - '/System/Library/PrivateFrameworks', - '/System/Library/QuickLook', - '/System/Library/QuickTime', - '/System/Library/QuickTimeJava', - '/System/Library/Recents', - '/System/Library/SDKSettingsPlist', - '/System/Library/Sandbox', - '/System/Library/Screen Savers', - '/System/Library/ScreenReader', - '/System/Library/ScriptingAdditions', - '/System/Library/ScriptingDefinitions', - '/System/Library/Security', - '/System/Library/Services', - '/System/Library/Sounds', - '/System/Library/Speech', - '/System/Library/Spelling', - '/System/Library/Spotlight', - '/System/Library/StartupItems', - '/System/Library/SyncServices', - '/System/Library/SystemConfiguration', - '/System/Library/SystemProfiler', - '/System/Library/Tcl', - '/System/Library/TextEncodings', - '/System/Library/User Template', - '/System/Library/UserEventPlugins', - '/System/Library/Video', - '/System/Library/WidgetResources', - '/User Information', - '/Users', - '/Volumes', - '/bin', - '/boot', - '/cores', - '/dev', - '/etc', - '/etc/X11', - '/etc/opt', - '/etc/sgml', - '/etc/xml', - '/home', - '/libexec', - '/lost+found', - '/media', - '/mnt', - '/net', - '/opt', - '/private', - '/private/etc', - '/private/tftpboot', - '/private/tmp', - '/private/var', - '/proc', - '/root', - '/sbin', - '/srv', - '/tmp', - '/usr', - '/usr/X11R6', - '/usr/bin', - '/usr/etc', - '/usr/include', - '/usr/lib', - '/usr/libexec', - '/usr/local', - '/usr/local/Cellar', - '/usr/local/Frameworks', - '/usr/local/Library', - '/usr/local/bin', - '/usr/local/etc', - '/usr/local/include', - '/usr/local/lib', - '/usr/local/libexec', - '/usr/local/opt', - '/usr/local/share', - '/usr/local/share/man', - '/usr/local/share/man/man1', - '/usr/local/share/man/man2', - '/usr/local/share/man/man3', - '/usr/local/share/man/man4', - '/usr/local/share/man/man5', - '/usr/local/share/man/man6', - '/usr/local/share/man/man7', - '/usr/local/share/man/man8', - '/usr/local/share/man/man9', - '/usr/local/share/man/mann', - '/usr/local/var', - '/usr/local/var/lib', - '/usr/local/var/lock', - '/usr/local/var/run', - '/usr/sbin', - '/usr/share', - '/usr/share/man', - '/usr/share/man/man1', - '/usr/share/man/man2', - '/usr/share/man/man3', - '/usr/share/man/man4', - '/usr/share/man/man5', - '/usr/share/man/man6', - '/usr/share/man/man7', - '/usr/share/man/man8', - '/usr/share/man/man9', - '/usr/share/man/mann', - '/usr/src', - '/var', - '/var/cache', - '/var/lib', - '/var/lock', - '/var/log', - '/var/mail', - '/var/run', - '/var/spool', - '/var/spool/mail', - '/var/tmp', - ].map{|x| Pathname.new(x)} - def self.all_matching(regexp, command) command.run('/usr/sbin/pkgutil', :args => [%Q{--pkgs=#{regexp}}]).stdout.split("\n").map do |package_id| new(package_id.chomp, command) @@ -250,7 +23,7 @@ def uninstall end odebug "Deleting pkg directories" _deepest_path_first(pkgutil_bom_dirs).each do |dir| - if dir.exist? and !SYSTEM_DIRS.include?(dir) + if dir.exist? and !Hbc::MacOS.undeletable?(dir) _with_full_permissions(dir) do _clean_broken_symlinks(dir) _clean_ds_store(dir) diff --git a/lib/hbc/staged.rb b/lib/hbc/staged.rb index 6c4781f6d695..fbce3f6a2995 100644 --- a/lib/hbc/staged.rb +++ b/lib/hbc/staged.rb @@ -3,7 +3,7 @@ def info_plist_file(index = 0) index = 0 if index == :first index = 1 if index == :second index = -1 if index == :last - @cask.staged_path.join(@cask.artifacts[:app].to_a.at(index).first, 'Contents', 'Info.plist') + Hbc.appdir.join(@cask.artifacts[:app].to_a.at(index).first, 'Contents', 'Info.plist') end def plist_exec(cmd) @@ -41,7 +41,7 @@ def set_ownership(paths, user: current_user, group: 'staff') end def current_user - Etc.getpwuid(Process.euid).name + Hbc::Utils.current_user end private diff --git a/lib/hbc/utils.rb b/lib/hbc/utils.rb index c343e7a5fa39..d50567b68971 100644 --- a/lib/hbc/utils.rb +++ b/lib/hbc/utils.rb @@ -159,6 +159,49 @@ def self.rmdir_if_possible(dir) end end + def self.permissions_rmtree(path, options = {}) + command = options.fetch(:command, Hbc::SystemCommand) + if path.respond_to?(:rmtree) and path.exist? + tried_permissions = false + tried_ownership = false + begin + path.rmtree + rescue StandardError => e + # in case of permissions problems + unless tried_permissions + # todo Better handling for the case where path is a symlink. + # The -h and -R flags cannot be combined, and behavior is + # dependent on whether the file argument has a trailing + # slash. This should do the right thing, but is fragile. + command.run('/usr/bin/chflags', must_succeed: false, + args: ['-R', '--', '000', path]) + command.run('/bin/chmod', must_succeed: false, + args: ['-R', '--', 'u+rwx', path]) + command.run('/bin/chmod', must_succeed: false, + args: ['-R', '-N', path]) + tried_permissions = true + retry # rmtree + end + unless tried_ownership + # in case of ownership problems + # todo Further examine files to see if ownership is the problem + # before using sudo+chown + ohai "Using sudo to gain ownership of path '#{path}'" + command.run('/usr/sbin/chown', :args => ['-R', '--', current_user, path], + :sudo => true) + tried_ownership = true + # retry chflags/chmod after chown + tried_permissions = false + retry # rmtree + end + end + end + end + + def self.current_user + Etc.getpwuid(Process.euid).name + end + # originally from Homebrew abv def self.cabv(dir) output = '' diff --git a/man/man1/brew-cask.1 b/man/man1/brew-cask.1 index 15ae20796e11..8251bb2e1e63 100644 --- a/man/man1/brew-cask.1 +++ b/man/man1/brew-cask.1 @@ -149,7 +149,7 @@ Give additional feedback during installation\. . .TP \fB\-\-appdir=\fR -Target location for Application links\. The default value is \fB~/Applications\fR\. +Target location for Application links\. The default value is \fB/Applications\fR\. . .TP \fB\-\-colorpickerdir=\fR diff --git a/spec/cask/artifact/binary_spec.rb b/spec/cask/artifact/binary_spec.rb index 224e7d76c216..144dae6985a3 100644 --- a/spec/cask/artifact/binary_spec.rb +++ b/spec/cask/artifact/binary_spec.rb @@ -68,4 +68,23 @@ expect(expected_path.exist?).to be true end + + context "binary is inside an app package" do + let(:cask) { + Hbc.load('with-embedded-binary').tap do |cask| + shutup do + InstallHelper::install_without_artifacts(cask) + end + end + } + + it "links the binary to the proper directory" do + shutup do + Hbc::Artifact::App.new(cask).install_phase + Hbc::Artifact::Binary.new(cask).install_phase + end + + expect(FileHelper.valid_alias?(expected_path)).to be true + end + end end diff --git a/spec/cask/macos_spec.rb b/spec/cask/macos_spec.rb new file mode 100644 index 000000000000..ec7c803ee41f --- /dev/null +++ b/spec/cask/macos_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe Hbc::MacOS do + it "says '/' is undeletable" do + expect(Hbc::MacOS).to be_undeletable( + '/') + expect(Hbc::MacOS).to be_undeletable( + '/.') + expect(Hbc::MacOS).to be_undeletable( + '/usr/local/Library/Taps/../../../..') + end + + it "says '/Applications' is undeletable" do + expect(Hbc::MacOS).to be_undeletable( + '/Applications') + expect(Hbc::MacOS).to be_undeletable( + '/Applications/') + expect(Hbc::MacOS).to be_undeletable( + '/Applications/.') + expect(Hbc::MacOS).to be_undeletable( + '/Applications/Mail.app/..') + end + + it "says the home directory is undeletable" do + expect(Hbc::MacOS).to be_undeletable( + Dir.home) + expect(Hbc::MacOS).to be_undeletable( + "#{ Dir.home }/") + expect(Hbc::MacOS).to be_undeletable( + "#{ Dir.home }/Documents/..") + end + + it "says the user library directory is undeletable" do + expect(Hbc::MacOS).to be_undeletable( + "#{ Dir.home }/Library") + expect(Hbc::MacOS).to be_undeletable( + "#{ Dir.home }/Library/") + expect(Hbc::MacOS).to be_undeletable( + "#{ Dir.home }/Library/.") + expect(Hbc::MacOS).to be_undeletable( + "#{ Dir.home }/Library/Preferences/..") + end + + it "says '/Applications/.app' is deletable" do + expect(Hbc::MacOS).not_to be_undeletable( + '/Applications/.app') + end + + it "says '/Applications/SnakeOil Professional.app' is deletable" do + expect(Hbc::MacOS).not_to be_undeletable( + '/Applications/SnakeOil Professional.app') + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6c96c4fe04b6..0aed1c7bc560 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -37,6 +37,7 @@ class TestCask < Cask; end Hbc.homebrew_repository = Hbc.homebrew_prefix Hbc.homebrew_tapspath = nil Hbc.binarydir = Hbc.homebrew_prefix.join('binarydir').join('bin') +Hbc.appdir = Pathname.new(TEST_TMPDIR).join('appdir') # making homebrew's cache dir allows us to actually download Casks in tests HOMEBREW_CACHE.mkpath diff --git a/spec/support/Casks/with-embedded-binary.rb b/spec/support/Casks/with-embedded-binary.rb new file mode 100644 index 000000000000..796f28c78bad --- /dev/null +++ b/spec/support/Casks/with-embedded-binary.rb @@ -0,0 +1,10 @@ +test_cask 'with-embedded-binary' do + version '1.2.3' + sha256 'fe052d3e77d92676775fd916ddb8942e72a565b844ea7f6d055474c99bb4e47b' + + url FileHelper.local_binary_url('AppWithEmbeddedBinary.zip') + homepage 'http://example.com/with-binary' + + app 'App.app' + binary "#{appdir}/App.app/Contents/MacOS/App/binary" +end diff --git a/spec/support/binaries/AppWithEmbeddedBinary.zip b/spec/support/binaries/AppWithEmbeddedBinary.zip new file mode 100644 index 000000000000..7c708038c5d3 Binary files /dev/null and b/spec/support/binaries/AppWithEmbeddedBinary.zip differ diff --git a/test/cask/accessibility_test.rb b/test/cask/accessibility_test.rb index 7b3d9823be7d..cfe769c65610 100644 --- a/test/cask/accessibility_test.rb +++ b/test/cask/accessibility_test.rb @@ -5,7 +5,8 @@ describe "Accessibility Access" do before do cask = Hbc.load('with-accessibility-access') - @installer = Hbc::Installer.new(cask, Hbc::FakeSystemCommand) + with_fake_command = { command: Hbc::FakeSystemCommand } + @installer = Hbc::Installer.new(cask, with_fake_command) end describe "install" do diff --git a/test/cask/artifact/alt_target_test.rb b/test/cask/artifact/alt_target_test.rb index 3cb1cfdd313d..34328c11359a 100644 --- a/test/cask/artifact/alt_target_test.rb +++ b/test/cask/artifact/alt_target_test.rb @@ -8,28 +8,15 @@ } describe 'activate to alternate target' do - it "activates the given apps using the proper target directory" do + it "installs the given apps using the proper target directory" do cask = local_alt_caffeine shutup do Hbc::Artifact::App.new(cask).install_phase end - TestHelper.valid_alias?(Hbc.appdir.join('AnotherName.app')).must_equal true - end - - it "creates metadata containing the alternate target name" do - cask = local_alt_caffeine - - shutup do - Hbc::Artifact::App.new(cask).install_phase - end - - Hbc::SystemCommand.run('/usr/bin/xattr', - :args => ['-p', - 'com.apple.metadata:kMDItemAlternateNames', - Hbc.appdir.join('AnotherName.app')], - :print_stderr => false).stdout.must_match(/AnotherName/) + File.ftype(Hbc.appdir.join('AnotherName.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('AnotherName.app')).must_equal false end it "works with an application in a subdir" do @@ -51,7 +38,8 @@ Hbc::Artifact::App.new(subdir_cask).install_phase end - TestHelper.valid_alias?(Hbc.appdir.join('AnotherName.app')).must_equal true + File.ftype(Hbc.appdir.join('AnotherName.app')).must_equal 'directory' + File.exist?(appsubdir.join('AnotherName.app')).must_equal false ensure if defined?(subdir_cask) shutup do @@ -64,39 +52,34 @@ it "only uses apps when they are specified" do cask = local_alt_caffeine - app_path = cask.staged_path.join('Caffeine.app') - FileUtils.cp_r app_path, app_path.sub('Caffeine.app', 'CaffeineAgain.app') + staged_app_path = cask.staged_path.join('Caffeine.app') + staged_app_copy = staged_app_path.sub('Caffeine.app', 'CaffeineAgain.app') + FileUtils.cp_r staged_app_path, staged_app_copy shutup do Hbc::Artifact::App.new(cask).install_phase end - TestHelper.valid_alias?(Hbc.appdir.join('AnotherName.app')).must_equal true - TestHelper.valid_alias?(Hbc.appdir.join('AnotherNameAgain.app')).must_equal false - end - - it "avoids clobbering an existing app by linking over it" do - cask = local_alt_caffeine - - Hbc.appdir.join('AnotherName.app').mkpath + File.ftype(Hbc.appdir.join('AnotherName.app')).must_equal 'directory' + File.exist?(staged_app_path).must_equal false - TestHelper.must_output(self, lambda { - Hbc::Artifact::App.new(cask).install_phase - }, "==> It seems there is already an App at '#{Hbc.appdir.join('AnotherName.app')}'; not linking.") - - Hbc.appdir.join('AnotherName.app').wont_be :symlink? + File.exist?(Hbc.appdir.join('AnotherNameAgain.app')).must_equal false + File.exist?(cask.staged_path.join('CaffeineAgain.app')).must_equal true end - it "happily clobbers an existing symlink" do + it "avoids clobbering an existing app by moving over it" do cask = local_alt_caffeine - Hbc.appdir.join('AnotherName.app').make_symlink('/tmp') + existing_app_path = Hbc.appdir.join('AnotherName.app') + existing_app_path.mkpath TestHelper.must_output(self, lambda { Hbc::Artifact::App.new(cask).install_phase - }, "==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('AnotherName.app')}'") + }, "==> It seems there is already an App at '#{existing_app_path}'; not moving.") + + source_path = cask.staged_path.join('Caffeine.app') - File.readlink(Hbc.appdir.join('AnotherName.app')).wont_equal '/tmp' + File.identical?(source_path, existing_app_path).must_equal false end end end diff --git a/test/cask/artifact/app_test.rb b/test/cask/artifact/app_test.rb index 0697484e551c..3276d6c333c3 100644 --- a/test/cask/artifact/app_test.rb +++ b/test/cask/artifact/app_test.rb @@ -8,14 +8,15 @@ } describe 'install_phase' do - it "activates the given apps using the proper target directory" do + it "installs the given apps using the proper target directory" do cask = local_caffeine shutup do Hbc::Artifact::App.new(cask).install_phase end - TestHelper.valid_alias?(Hbc.appdir.join('Caffeine.app')).must_equal true + File.ftype(Hbc.appdir.join('Caffeine.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('Caffeine.app')).must_equal false end it "works with an application in a subdir" do @@ -37,7 +38,8 @@ Hbc::Artifact::App.new(subdir_cask).install_phase end - TestHelper.valid_alias?(Hbc.appdir.join('Caffeine.app')).must_equal true + File.ftype(Hbc.appdir.join('Caffeine.app')).must_equal 'directory' + File.exist?(appsubdir.join('Caffeine.app')).must_equal false ensure if defined?(subdir_cask) shutup do @@ -50,39 +52,189 @@ it "only uses apps when they are specified" do cask = local_caffeine - app_path = cask.staged_path.join('Caffeine.app') - FileUtils.cp_r app_path, app_path.sub('Caffeine.app', 'CaffeineAgain.app') + staged_app_path = cask.staged_path.join('Caffeine.app') + staged_app_copy = staged_app_path.sub('Caffeine.app', 'CaffeineAgain.app') + FileUtils.cp_r staged_app_path, staged_app_copy shutup do Hbc::Artifact::App.new(cask).install_phase end - TestHelper.valid_alias?(Hbc.appdir.join('Caffeine.app')).must_equal true - TestHelper.valid_alias?(Hbc.appdir.join('CaffeineAgain.app')).must_equal false + File.ftype(Hbc.appdir.join('Caffeine.app')).must_equal 'directory' + File.exist?(staged_app_path).must_equal false + + File.exist?(Hbc.appdir.join('CaffeineAgain.app')).must_equal false + File.exist?(cask.staged_path.join('CaffeineAgain.app')).must_equal true + end + + describe "when the target already exists" do + let(:target_path) { + target_path = Hbc.appdir.join('Caffeine.app') + target_path.mkpath + target_path + } + + it "avoids clobbering an existing app" do + cask = local_caffeine + + TestHelper.must_output(self, lambda { + Hbc::Artifact::App.new(cask).install_phase + }, "==> It seems there is already an App at '#{target_path}'; not moving.") + + source_path = cask.staged_path.join('Caffeine.app') + + File.identical?(source_path, target_path).must_equal false + + contents_path = target_path.join('Contents/Info.plist') + File.exist?(contents_path).must_equal false + end + + describe "given the force option" do + let(:install_phase) { + lambda { |given_options = {}| + options = { force: true }.merge(given_options) + Hbc::Artifact::App.new(local_caffeine, options).install_phase + } + } + + let(:chmod_cmd) { + ['/bin/chmod', '-R', '--', 'u+rwx', target_path] + } + + let(:chmod_n_cmd) { + ['/bin/chmod', '-R', '-N', target_path] + } + + let(:chflags_cmd) { + ['/usr/bin/chflags', '-R', '--', '000', target_path] + } + + before do + Hbc::Utils.stubs(current_user: 'fake_user') + end + + describe "target is both writable and user-owned" do + it "overwrites the existing app" do + cask = local_caffeine + + expected = [ + "==> It seems there is already an App at '#{target_path}'; overwriting.", + "==> Removing App: '#{target_path}'", + "==> Moving App 'Caffeine.app' to '#{target_path}'" + ] + TestHelper.must_output(self, install_phase, + expected.join("\n")) + + source_path = cask.staged_path.join('Caffeine.app') + + File.exist?(source_path).must_equal false + File.ftype(target_path).must_equal 'directory' + + contents_path = target_path.join('Contents/Info.plist') + File.exist?(contents_path).must_equal true + end + end + + describe "target is user-owned but contains read-only files" do + before do + system '/usr/bin/touch', '--', "#{ target_path }/foo" + system '/bin/chmod', '--', '0555', target_path + end + + it "tries to make the target world-writable" do + Hbc::FakeSystemCommand.expect_and_pass_through(chflags_cmd) + Hbc::FakeSystemCommand.expect_and_pass_through(chmod_cmd) + Hbc::FakeSystemCommand.expect_and_pass_through(chmod_n_cmd) + shutup do + install_phase.call(command: Hbc::FakeSystemCommand) + end + end + + it "overwrites the existing app" do + cask = local_caffeine + + expected = [ + "==> It seems there is already an App at '#{target_path}'; overwriting.", + "==> Removing App: '#{target_path}'", + "==> Moving App 'Caffeine.app' to '#{target_path}'" + ] + TestHelper.must_output(self, install_phase, + expected.join("\n")) + + source_path = cask.staged_path.join('Caffeine.app') + + File.exist?(source_path).must_equal false + File.ftype(target_path).must_equal 'directory' + + contents_path = target_path.join('Contents/Info.plist') + File.exist?(contents_path).must_equal true + end + + after do + system '/bin/chmod', '--', '0755', target_path + end + end + end end - it "avoids clobbering an existing app by linking over it" do + it "gives a warning if the source doesn't exist" do cask = local_caffeine + staged_app_path = cask.staged_path.join('Caffeine.app') + staged_app_path.rmtree - Hbc.appdir.join('Caffeine.app').mkpath + installation = -> { Hbc::Artifact::App.new(cask).install_phase } + message = "It seems the App source is not there: '#{staged_app_path}'" + + error = installation.must_raise(Hbc::CaskError) + error.message.must_equal message + end + end + + describe "uninstall_phase" do + it "deletes managed apps" do + cask = local_caffeine - TestHelper.must_output(self, lambda { + shutup do Hbc::Artifact::App.new(cask).install_phase - }, "==> It seems there is already an App at '#{Hbc.appdir.join('Caffeine.app')}'; not linking.") + Hbc::Artifact::App.new(cask).uninstall_phase + end - Hbc.appdir.join('Caffeine.app').wont_be :symlink? + app_path = Hbc.appdir.join('Caffeine.app') + File.exist?(app_path).must_equal false end + end - it "happily clobbers an existing symlink" do + describe "summary" do + it "returns the correct english_description" do cask = local_caffeine - Hbc.appdir.join('Caffeine.app').make_symlink('/tmp') + description = Hbc::Artifact::App.new(cask).summary[:english_description] - TestHelper.must_output(self, lambda { - Hbc::Artifact::App.new(cask).install_phase - }, "==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('Caffeine.app')}'") + description.must_equal 'Apps managed by brew-cask:' + end + + describe "app is correctly installed" do + it "returns the path to the app" do + cask = local_caffeine + shutup { Hbc::Artifact::App.new(cask).install_phase } + + contents = Hbc::Artifact::App.new(cask).summary[:contents] + app_path = Hbc.appdir.join('Caffeine.app') - File.readlink(Hbc.appdir.join('Caffeine.app')).wont_equal '/tmp' + contents.must_equal ["'#{app_path}'"] + end + end + + describe "app is missing" do + it "returns a warning and the supposed path to the app" do + cask = local_caffeine + + contents = Hbc::Artifact::App.new(cask).summary[:contents] + app_path = Hbc.appdir.join('Caffeine.app') + + contents.size.must_equal 1 + contents[0].must_match(/.*Missing App.*: '#{app_path}'/) + end end end end diff --git a/test/cask/artifact/generic_artifact_test.rb b/test/cask/artifact/generic_artifact_test.rb index ad7782f7cc77..ad4349447ac0 100644 --- a/test/cask/artifact/generic_artifact_test.rb +++ b/test/cask/artifact/generic_artifact_test.rb @@ -21,31 +21,24 @@ }.must_raise(Hbc::CaskInvalidError) end - it "links the artifact to the proper directory" do + it "moves the artifact to the proper directory" do shutup do Hbc::Artifact::Artifact.new(cask).install_phase end - TestHelper.valid_alias?(expected_path).must_equal true + File.ftype(Hbc.appdir.join('Caffeine.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('Caffeine.app')).must_equal false end - it "avoids clobbering an existing artifact by linking over it" do + it "avoids clobbering an existing artifact" do FileUtils.touch expected_path shutup do Hbc::Artifact::Artifact.new(cask).install_phase end - expected_path.wont_be :symlink? - end - - it "clobbers an existing symlink" do - expected_path.make_symlink('/tmp') - - shutup do - Hbc::Artifact::Artifact.new(cask).install_phase - end + source_path = cask.staged_path.join('Caffeine.app') - File.readlink(expected_path).wont_equal '/tmp' + File.identical?(source_path, expected_path).must_equal false end end diff --git a/test/cask/artifact/pkg_test.rb b/test/cask/artifact/pkg_test.rb index 8e384a62a1e8..7776444ffc0c 100644 --- a/test/cask/artifact/pkg_test.rb +++ b/test/cask/artifact/pkg_test.rb @@ -10,7 +10,8 @@ describe 'install_phase' do it 'runs the system installer on the specified pkgs' do - pkg = Hbc::Artifact::Pkg.new(@cask, Hbc::FakeSystemCommand) + pkg = Hbc::Artifact::Pkg.new(@cask, + command: Hbc::FakeSystemCommand) Hbc::FakeSystemCommand.expects_command(['/usr/bin/sudo', '-E', '--', '/usr/sbin/installer', '-pkg', @cask.staged_path.join('MyFancyPkg','Fancy.pkg'), '-target', '/']) @@ -22,7 +23,8 @@ describe 'uninstall_phase' do it 'does nothing, because the uninstall_phase method is a no-op' do - pkg = Hbc::Artifact::Pkg.new(@cask, Hbc::FakeSystemCommand) + pkg = Hbc::Artifact::Pkg.new(@cask, + command: Hbc::FakeSystemCommand) shutup do pkg.uninstall_phase end diff --git a/test/cask/artifact/suite_test.rb b/test/cask/artifact/suite_test.rb index 7310b175f13d..40fe26acc636 100644 --- a/test/cask/artifact/suite_test.rb +++ b/test/cask/artifact/suite_test.rb @@ -9,13 +9,16 @@ let(:expected_path) { Hbc.appdir.join('caffeine_suite') } + let(:source_path) { cask.staged_path.join('caffeine_suite') } - it "links the suite to the proper directory" do + it "moves the suite to the proper directory" do shutup do Hbc::Artifact::Suite.new(cask).install_phase end - TestHelper.valid_alias?(expected_path).must_equal true + expected_path.must_be :directory? + TestHelper.valid_alias?(expected_path).must_equal false + File.exist?(source_path).must_equal false end it "creates a suite containing the expected app" do @@ -26,23 +29,13 @@ expected_path.join('Caffeine.app').must_be :exist? end - it "avoids clobbering an existing suite by linking over it" do + it "avoids clobbering an existing suite by moving over it" do FileUtils.touch expected_path shutup do Hbc::Artifact::Suite.new(cask).install_phase end - expected_path.wont_be :symlink? - end - - it "clobbers an existing symlink" do - expected_path.make_symlink('/tmp') - - shutup do - Hbc::Artifact::Suite.new(cask).install_phase - end - - File.readlink(expected_path).wont_equal '/tmp' + File.identical?(source_path, expected_path).must_equal false end end diff --git a/test/cask/artifact/two_apps_correct_test.rb b/test/cask/artifact/two_apps_correct_test.rb index 7b29093d2f2c..7bd2ef0b06ee 100644 --- a/test/cask/artifact/two_apps_correct_test.rb +++ b/test/cask/artifact/two_apps_correct_test.rb @@ -7,122 +7,91 @@ end } + let(:local_two_apps_subdir) { + Hbc.load('with-two-apps-subdir').tap do |cask| + TestHelper.install_without_artifacts(cask) + end + } + describe 'multiple apps' do - it "activates both apps using the proper target directory" do + it "installs both apps using the proper target directory" do cask = local_two_apps_caffeine shutup do Hbc::Artifact::App.new(cask).install_phase end - TestHelper.valid_alias?(Hbc.appdir.join('Caffeine.app')).must_equal true - TestHelper.valid_alias?(Hbc.appdir.join('AnotherName.app')).must_equal true + File.ftype(Hbc.appdir.join('Caffeine.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('Caffeine.app')).must_equal false + + File.ftype(Hbc.appdir.join('Caffeine-2.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('Caffeine-2.app')).must_equal false end it "works with an application in a subdir" do - subdir_cask = Hbc::Cask.new('alt-subdir-two-apps') do - url TestHelper.local_binary_url('caffeine.zip') - homepage 'http://example.com/local-caffeine' - version '1.2.3' - sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853' - app 'subdir/Caffeine.app' - app 'subdir/Caffeine.app', :target => 'AnotherName.app' - end - - begin - TestHelper.install_without_artifacts(subdir_cask) - - appsubdir = subdir_cask.staged_path.join('subdir').tap(&:mkpath) - FileUtils.mv(subdir_cask.staged_path.join('Caffeine.app'), appsubdir) - - shutup do - Hbc::Artifact::App.new(subdir_cask).install_phase - end + cask = local_two_apps_subdir + TestHelper.install_without_artifacts(cask) - TestHelper.valid_alias?(Hbc.appdir.join('Caffeine.app')).must_equal true - TestHelper.valid_alias?(Hbc.appdir.join('AnotherName.app')).must_equal true - ensure - if defined?(subdir_cask) - shutup do - Hbc::Installer.new(subdir_cask).uninstall - end - end + shutup do + Hbc::Artifact::App.new(cask).install_phase end - end - - # @@@ todo - # it "only uses apps when they are specified" do - # cask = local_two_apps_caffeine - # - # app_path = cask.staged_path.join('Caffeine.app') - # FileUtils.cp_r app_path, app_path.sub('Caffeine.app', 'CaffeineAgain.app') - # - # shutup do - # Hbc::Artifact::App.new(cask).install_phase - # end - # - # TestHelper.valid_alias?(Hbc.appdir.join('AnotherName.app')).must_equal true - # TestHelper.valid_alias?(Hbc.appdir.join('AnotherNameAgain.app').must_equal false - # end - - it "avoids clobbering an existing app by linking over it (link 1)" do - cask = local_two_apps_caffeine - Hbc.appdir.join('Caffeine.app').mkpath - - TestHelper.must_output(self, lambda { - Hbc::Artifact::App.new(cask).install_phase - }, <<-MESSAGE.undent.chomp) - ==> It seems there is already an App at '#{Hbc.appdir.join('Caffeine.app')}'; not linking. - ==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('AnotherName.app')}' - MESSAGE + File.ftype(Hbc.appdir.join('Caffeine.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('Caffeine.app')).must_equal false - Hbc.appdir.join('Caffeine.app').wont_be :symlink? + File.ftype(Hbc.appdir.join('Caffeine-2.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('Caffeine-2.app')).must_equal false end - it "avoids clobbering an existing app by linking over it (link 2)" do + it "only uses apps when they are specified" do cask = local_two_apps_caffeine - Hbc.appdir.join('AnotherName.app').mkpath + app_path = cask.staged_path.join('Caffeine.app') + FileUtils.cp_r app_path, app_path.sub('Caffeine.app', 'CaffeineAgain.app') - TestHelper.must_output(self, lambda { + shutup do Hbc::Artifact::App.new(cask).install_phase - }, <<-MESSAGE.undent.chomp) - ==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('Caffeine.app')}' - ==> It seems there is already an App at '#{Hbc.appdir.join('AnotherName.app')}'; not linking. - MESSAGE + end + + File.ftype(Hbc.appdir.join('Caffeine.app')).must_equal 'directory' + File.exist?(cask.staged_path.join('Caffeine.app')).must_equal false - Hbc.appdir.join('AnotherName.app').wont_be :symlink? + File.exist?(Hbc.appdir.join('CaffeineAgain.app')).must_equal false + File.exist?(cask.staged_path.join('CaffeineAgain.app')).must_equal true end - it "happily clobbers an existing symlink (link 1)" do + it "avoids clobbering an existing app (app 1)" do cask = local_two_apps_caffeine - Hbc.appdir.join('Caffeine.app').make_symlink('/tmp') + Hbc.appdir.join('Caffeine.app').mkpath TestHelper.must_output(self, lambda { Hbc::Artifact::App.new(cask).install_phase }, <<-MESSAGE.undent.chomp) - ==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('Caffeine.app')}' - ==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('AnotherName.app')}' + ==> Moving App 'Caffeine-2.app' to '#{Hbc.appdir.join('Caffeine-2.app')}' + ==> It seems there is already an App at '#{Hbc.appdir.join('Caffeine.app')}'; not moving. MESSAGE - File.readlink(Hbc.appdir.join('Caffeine.app')).wont_equal '/tmp' + source_path = cask.staged_path.join('Caffeine.app') + + File.identical?(source_path, Hbc.appdir.join('Caffeine.app')).must_equal false end - it "happily clobbers an existing symlink (link 2)" do + it "avoids clobbering an existing app (app 2)" do cask = local_two_apps_caffeine - Hbc.appdir.join('AnotherName.app').make_symlink('/tmp') + Hbc.appdir.join('Caffeine-2.app').mkpath TestHelper.must_output(self, lambda { Hbc::Artifact::App.new(cask).install_phase }, <<-MESSAGE.undent.chomp) - ==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('Caffeine.app')}' - ==> Symlinking App 'Caffeine.app' to '#{Hbc.appdir.join('AnotherName.app')}' + ==> It seems there is already an App at '#{Hbc.appdir.join('Caffeine-2.app')}'; not moving. + ==> Moving App 'Caffeine.app' to '#{Hbc.appdir.join('Caffeine.app')}' MESSAGE - File.readlink(Hbc.appdir.join('AnotherName.app')).wont_equal '/tmp' + source_path = cask.staged_path.join('Caffeine-2.app') + + File.identical?(source_path, Hbc.appdir.join('Caffeine-2.app')).must_equal false end end end diff --git a/test/cask/artifact/uninstall_test.rb b/test/cask/artifact/uninstall_test.rb index 316a2723c011..2df6cc2dc8c2 100644 --- a/test/cask/artifact/uninstall_test.rb +++ b/test/cask/artifact/uninstall_test.rb @@ -2,7 +2,10 @@ describe Hbc::Artifact::Uninstall do let(:cask) { Hbc.load('with-installable') } - let(:uninstall_artifact) { Hbc::Artifact::Uninstall.new(cask, Hbc::FakeSystemCommand) } + + let(:uninstall_artifact) do + Hbc::Artifact::Uninstall.new(cask, command: Hbc::FakeSystemCommand) + end before { shutup do diff --git a/test/cask/artifact/zap_test.rb b/test/cask/artifact/zap_test.rb index 471884170237..98a0e6a9fc06 100644 --- a/test/cask/artifact/zap_test.rb +++ b/test/cask/artifact/zap_test.rb @@ -4,7 +4,10 @@ # - test that zap removes an alternate version of the same Cask describe Hbc::Artifact::Zap do let(:cask) { Hbc.load('with-installable') } - let(:zap_artifact) { Hbc::Artifact::Zap.new(cask, Hbc::FakeSystemCommand) } + + let(:zap_artifact) do + Hbc::Artifact::Zap.new(cask, command: Hbc::FakeSystemCommand) + end before { shutup do diff --git a/test/cask/cli/install_test.rb b/test/cask/cli/install_test.rb index 199cf965bbcd..b64afc680a67 100644 --- a/test/cask/cli/install_test.rb +++ b/test/cask/cli/install_test.rb @@ -7,9 +7,9 @@ end Hbc.load('local-transmission').must_be :installed? - Hbc.appdir.join('Transmission.app').must_be :symlink? + Hbc.appdir.join('Transmission.app').must_be :directory? Hbc.load('local-caffeine').must_be :installed? - Hbc.appdir.join('Caffeine.app').must_be :symlink? + Hbc.appdir.join('Caffeine.app').must_be :directory? end it "skips double install (without nuking existing installation)" do @@ -39,7 +39,7 @@ TestHelper.must_output(self, lambda { Hbc::CLI::Install.run('local-transmission', '--force') - }, %r{==> Success! local-transmission staged at '#{Hbc.caskroom}/local-transmission/2.61' \(487 files, 11M\)}) + }, %r{==> Success! local-transmission staged at '#{Hbc.caskroom}/local-transmission/2.61' \(0B\)}) end it "properly handles Casks that are not present" do diff --git a/test/cask/cli/list_test.rb b/test/cask/cli/list_test.rb index 5515fdba3180..8f849f3b360b 100644 --- a/test/cask/cli/list_test.rb +++ b/test/cask/cli/list_test.rb @@ -41,16 +41,17 @@ caffeine, transmission = casks - # App Symlinks sections are empty below because the expected links - # aren't created under the test harness. Todo: managed links should - # be fully mocked and confirmed here. + shutup { Hbc::Artifact::App.new(transmission).install_phase } + lambda { Hbc::CLI::List.run('local-transmission', 'local-caffeine') }.must_output <<-OUTPUT.gsub(/^ */, '') - ==> App Symlinks managed by brew-cask: + ==> Apps managed by brew-cask: + '#{Hbc.appdir.join('Transmission.app')}' ==> Staged content: - #{transmission.staged_path} (489 files) - ==> App Symlinks managed by brew-cask: + #{transmission.staged_path} (0 files) + ==> Apps managed by brew-cask: + Missing App: '#{Hbc.appdir.join('Caffeine.app')}' ==> Staged content: #{caffeine.staged_path} (13 files) OUTPUT diff --git a/test/cask/cli/uninstall_test.rb b/test/cask/cli/uninstall_test.rb index e007ed756617..4fae3f63de21 100644 --- a/test/cask/cli/uninstall_test.rb +++ b/test/cask/cli/uninstall_test.rb @@ -36,9 +36,9 @@ end caffeine.wont_be :installed? - Hbc.appdir.join('Transmission.app').wont_be :symlink? + File.exist?(Hbc.appdir.join('Transmission.app')).must_equal false transmission.wont_be :installed? - Hbc.appdir.join('Caffeine.app').wont_be :symlink? + File.exist?(Hbc.appdir.join('Caffeine.app')).must_equal false end describe "when Casks have been renamed" do diff --git a/test/cask/dsl/postflight_test.rb b/test/cask/dsl/postflight_test.rb index 3698ef9d5a16..2e92b8c79d34 100644 --- a/test/cask/dsl/postflight_test.rb +++ b/test/cask/dsl/postflight_test.rb @@ -9,22 +9,4 @@ it_behaves_like Hbc::Staged do let(:staged) { @dsl } end - - it "can suppress move to applications folder alert " do - @dsl.stubs(:bundle_identifier => 'com.example.BasicCask') - - Hbc::FakeSystemCommand.expects_command( - ['/usr/bin/defaults', 'write', 'com.example.BasicCask', 'moveToApplicationsFolderAlertSuppress', '-bool', 'true'] - ) - @dsl.suppress_move_to_applications - end - - it "can suppress move to applications folder alert with a different key" do - @dsl.stubs(:bundle_identifier => 'com.example.BasicCask') - - Hbc::FakeSystemCommand.expects_command( - ['/usr/bin/defaults', 'write', 'com.example.BasicCask', 'suppressMoveToApplications', '-bool', 'true'] - ) - @dsl.suppress_move_to_applications :key => 'suppressMoveToApplications' - end end diff --git a/test/cask/dsl_test.rb b/test/cask/dsl_test.rb index 9db7f60ad18b..0661beb9c759 100644 --- a/test/cask/dsl_test.rb +++ b/test/cask/dsl_test.rb @@ -405,4 +405,26 @@ def caveats; <<-EOS.undent cask.auto_updates.must_equal true end end + + describe "appdir" do + it "allows interpolation of the appdir value in stanzas" do + cask = Hbc.load('appdir-interpolation') + cask.artifacts[:binary].first.must_equal ["#{Hbc.appdir}/some/path"] + end + + it "does not include a trailing slash" do + original_appdir = Hbc.appdir + Hbc.appdir = "#{original_appdir}/" + + begin + cask = Hbc::Cask.new('appdir-trailing-slash') do + binary "#{appdir}/some/path" + end + + cask.artifacts[:binary].first.must_equal ["#{original_appdir}/some/path"] + ensure + Hbc.appdir = original_appdir + end + end + end end diff --git a/test/cask/installer_test.rb b/test/cask/installer_test.rb index ba467a117370..baa8065bb639 100644 --- a/test/cask/installer_test.rb +++ b/test/cask/installer_test.rb @@ -11,7 +11,7 @@ dest_path = Hbc.caskroom.join('local-caffeine',caffeine.version) dest_path.must_be :directory? - application = dest_path.join('Caffeine.app') + application = Hbc.appdir.join('Caffeine.app') application.must_be :directory? end @@ -24,7 +24,7 @@ dest_path = Hbc.caskroom.join('local-transmission',transmission.version) dest_path.must_be :directory? - application = dest_path.join('Transmission.app') + application = Hbc.appdir.join('Transmission.app') application.must_be :directory? end @@ -37,7 +37,7 @@ dest_path = Hbc.caskroom.join('tarball',tarball.version) dest_path.must_be :directory? - application = dest_path.join('Tarball.app') + application = Hbc.appdir.join('Tarball.app') application.must_be :directory? end @@ -53,7 +53,7 @@ dest_path = Hbc.caskroom.join('cab-container',cab_container.version) dest_path.must_be :directory? - application = dest_path.join('cabcontainer','Application.app') + application = Hbc.appdir.join('Application.app') application.must_be :directory? end @@ -65,7 +65,7 @@ end dest_path = Hbc.caskroom.join('adobe-air-container',air_container.version) dest_path.must_be :directory? - application = dest_path.join('GMDesk.app') + application = Hbc.appdir.join('GMDesk.app') application.must_be :directory? end @@ -81,7 +81,7 @@ dest_path = Hbc.caskroom.join('sevenzip-container',sevenzip_container.version) dest_path.must_be :directory? - application = dest_path.join('sevenzipcontainer','Application.app') + application = Hbc.appdir.join('Application.app') application.must_be :directory? end @@ -94,7 +94,7 @@ dest_path = Hbc.caskroom.join('xar-container',xar_container.version) dest_path.must_be :directory? - application = dest_path.join('xarcontainer','Application.app') + application = Hbc.appdir.join('Application.app') application.must_be :directory? end @@ -110,7 +110,7 @@ dest_path = Hbc.caskroom.join('stuffit-container',stuffit_container.version) dest_path.must_be :directory? - application = dest_path.join('sheldonmac','v1.0') + application = Hbc.appdir.join('sheldonmac','v1.0') application.must_be :directory? end @@ -126,7 +126,7 @@ dest_path = Hbc.caskroom.join('rar-container',rar_container.version) dest_path.must_be :directory? - application = dest_path.join('rarcontainer','Application.app') + application = Hbc.appdir.join('Application.app') application.must_be :directory? end @@ -139,7 +139,7 @@ dest_path = Hbc.caskroom.join('bzipped-asset',asset.version) dest_path.must_be :directory? - file = dest_path.join("bzipped-asset-#{asset.version}") + file = Hbc.appdir.join("bzipped-asset-#{asset.version}") file.must_be :file? end @@ -152,7 +152,7 @@ dest_path = Hbc.caskroom.join('gzipped-asset',asset.version) dest_path.must_be :directory? - file = dest_path.join("gzipped-asset-#{asset.version}") + file = Hbc.appdir.join("gzipped-asset-#{asset.version}") file.must_be :file? end @@ -220,11 +220,11 @@ it "allows already-installed Casks which auto-update to be installed if force is provided" do auto_updates = Hbc.load('auto-updates') auto_updates.installed?.must_equal false - installer = Hbc::Installer.new(auto_updates) - shutup { installer.install } + shutup { Hbc::Installer.new(auto_updates).install } + shutup { - installer.install(true) + Hbc::Installer.new(auto_updates, force: true).install } # wont_raise end @@ -243,11 +243,11 @@ it "allows already-installed Casks to be installed if force is provided" do transmission = Hbc.load('local-transmission') transmission.installed?.must_equal false - installer = Hbc::Installer.new(transmission) - shutup { installer.install } + shutup { Hbc::Installer.new(transmission).install } + shutup { - installer.install(true) + Hbc::Installer.new(transmission, force: true).install } # wont_raise end @@ -283,7 +283,7 @@ end dest_path = Hbc.appdir.join('MyNestedApp.app') - TestHelper.valid_alias?(dest_path).must_equal true + File.ftype(dest_path).must_equal 'directory' end it "generates and finds a timestamped metadata directory for an installed Cask" do @@ -329,11 +329,10 @@ it "uninstalls all versions if force is set" do caffeine = Hbc.load('local-caffeine') - installer = Hbc::Installer.new(caffeine) mutated_version = caffeine.version + '.1' shutup do - installer.install + Hbc::Installer.new(caffeine).install end Hbc.caskroom.join('local-caffeine',caffeine.version).must_be :directory? @@ -343,7 +342,7 @@ Hbc.caskroom.join('local-caffeine',mutated_version).must_be :directory? shutup do - installer.uninstall(true) + Hbc::Installer.new(caffeine, force: true).uninstall end Hbc.caskroom.join('local-caffeine',caffeine.version).wont_be :directory? diff --git a/test/support/Casks/appdir-interpolation.rb b/test/support/Casks/appdir-interpolation.rb new file mode 100644 index 000000000000..6aa3f29c3474 --- /dev/null +++ b/test/support/Casks/appdir-interpolation.rb @@ -0,0 +1,9 @@ +test_cask 'appdir-interpolation' do + version '2.61' + sha256 'd26d7481cf1229f879c05e11cbdf440d99db6d6342f26c73d8ba7861b975532f' + + url TestHelper.local_binary_url('transmission-2.61.dmg') + homepage 'http://example.com/appdir-interpolation' + + binary "#{appdir}/some/path" +end diff --git a/test/support/Casks/with-two-apps-correct.rb b/test/support/Casks/with-two-apps-correct.rb index a410068148d9..a0b142528aa3 100644 --- a/test/support/Casks/with-two-apps-correct.rb +++ b/test/support/Casks/with-two-apps-correct.rb @@ -1,10 +1,10 @@ test_cask 'with-two-apps-correct' do version '1.2.3' - sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853' + sha256 'c0c79dce9511c80603328013dbbcb80b859cc8b9190660b6832b5f0e60d74c82' - url TestHelper.local_binary_url('caffeine.zip') + url TestHelper.local_binary_url('2_app_caffeine.zip') homepage 'http://example.com/local-caffeine' app 'Caffeine.app' - app 'Caffeine.app', target: 'AnotherName.app' + app 'Caffeine-2.app' end diff --git a/test/support/Casks/with-two-apps-subdir.rb b/test/support/Casks/with-two-apps-subdir.rb new file mode 100644 index 000000000000..61adefab679e --- /dev/null +++ b/test/support/Casks/with-two-apps-subdir.rb @@ -0,0 +1,10 @@ +test_cask 'with-two-apps-subdir' do + version '1.2.3' + sha256 '03edce6992a6095e120dcfadf7049158589ae6f0548c145ed1b1c6f2883f6dca' + + url TestHelper.local_binary_url('2_app_subdir.zip') + homepage 'http://example.com/local-caffeine' + + app 'subdir/Caffeine.app' + app 'subdir/Caffeine-2.app' +end diff --git a/test/support/binaries/2_app_caffeine.zip b/test/support/binaries/2_app_caffeine.zip new file mode 100755 index 000000000000..a678f7c11bee Binary files /dev/null and b/test/support/binaries/2_app_caffeine.zip differ diff --git a/test/support/binaries/2_app_subdir.zip b/test/support/binaries/2_app_subdir.zip new file mode 100755 index 000000000000..27637a731daa Binary files /dev/null and b/test/support/binaries/2_app_subdir.zip differ diff --git a/test/support/fake_system_command.rb b/test/support/fake_system_command.rb index a98686dcae97..310f36e41286 100644 --- a/test/support/fake_system_command.rb +++ b/test/support/fake_system_command.rb @@ -26,6 +26,13 @@ def self.expects_command(command, response='', times=1) expectations[command] = times end + def self.expect_and_pass_through(command, times=1) + pass_through = lambda do |command, options| + Hbc::SystemCommand.run(command, options) + end + expects_command(command, pass_through, times) + end + def self.verify_expectations! expectations.each do |command, times| unless system_calls[command] == times @@ -34,13 +41,19 @@ def self.verify_expectations! end end - def self.run(command, options={}) - command = Hbc::SystemCommand._process_options(command, options) + def self.run(command_string, options={}) + command = Hbc::SystemCommand._process_options(command_string, options) unless responses.key?(command) fail("no response faked for #{command.inspect}, faked responses are: #{responses.inspect}") end system_calls[command] += 1 - Hbc::SystemCommand::Result.new(command, responses[command], '', 0) + + response = responses[command] + if response.respond_to?(:call) + response.call(command_string, options) + else + Hbc::SystemCommand::Result.new(command, response, '', 0) + end end def self.run!(command, options={}) diff --git a/test/support/shared_examples/staged.rb b/test/support/shared_examples/staged.rb index 09d92e5ee66a..e51578c19e12 100644 --- a/test/support/shared_examples/staged.rb +++ b/test/support/shared_examples/staged.rb @@ -21,7 +21,7 @@ end it "can get the Info.plist file for the primary app" do - staged.info_plist_file.to_s.must_include 'basic-cask/1.2.3/TestCask.app/Contents/Info.plist' + staged.info_plist_file.to_s.must_include Hbc.appdir.join('TestCask.app/Contents/Info.plist') end it "can execute commands on the Info.plist file" do diff --git a/test/test_helper.rb b/test/test_helper.rb index 3a832eac8bd5..9ee1c6e2eb50 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -98,12 +98,15 @@ def self.fake_response_for(*args) Hbc::FakeFetcher.fake_response_for(*args) end - def self.must_output(test, lambda, expected) + def self.must_output(test, lambda, expected = nil) out, err = test.capture_subprocess_io do lambda.call end - if expected.is_a? Regexp + case + when block_given? + yield (out+err).chomp + when expected.is_a?(Regexp) (out+err).chomp.must_match expected else (out+err).chomp.must_equal expected.gsub(/^ */, '')