homebrew-cask/lib/cask/cli/alfred.rb

195 lines
5.9 KiB
Ruby

require 'rubygems'
class Cask::CLI::Alfred < Cask::CLI::Base
DEFAULT_SCOPES = [
'/Applications',
'/Applications/Xcode.app/Contents/Applications',
'/Developer/Applications',
'/Library/PreferencePanes',
'/System/Library/CoreServices/Applications',
'/System/Library/PreferencePanes',
'~/Library/Caches/Metadata/',
'~/Library/Mobile Documents/',
'~/Library/PreferencePanes'
]
PRIMARY_DOMAIN = 'com.runningwithcrayons.Alfred-Preferences'
PRIMARY_SCOPES_KEY = 'features.defaultresults.scope'
# http://www.alfredforum.com/topic/4810-alfred%E2%80%99s-scope-can-no-longer-be-changed-programatically/?p=29434
LOCALPREFS_SUBPATH = '/Alfred.alfredpreferences/preferences/local/*/features/defaultresults/prefs.plist'
LOCALPREFS_SYNCDIR_KEY = 'syncfolder'
LOCALPREFS_SCOPES_KEY = 'scope'
def self.run(*args)
subcommand = args.first
if args.length > 1 && args.last.is_a?(Class)
@system_command = args.last
else
@system_command = Cask::SystemCommand
end
case subcommand
when 'link' then link
when 'unlink' then unlink
when 'status' then status
else
usage
end
end
def self.help
"used to modify Alfred's scope to include the Caskroom"
end
def self.assert_installed
unless alfred_2_installed?
opoo "Could not find Alfred 2 preferences. Alfred 2 is probably not installed."
end
if alfred_localprefs? and localprefs_scopes_files.size < 1
raise CaskError.new "Alfred 2.4+ detected, but local preferences file not found. Try running Alfred first."
end
alfred_2_installed?
end
def self.link
return unless assert_installed
if linked?
opoo "Alfred appears to be already linked. Updating defaults anyway."
end
odebug 'Linking Alfred scopes'
# this silly ternary operation is for precise compat with Ruby 1.8
save_alfred_scopes( alfred_scopes.include?(Cask.caskroom.to_s) ? alfred_scopes : alfred_scopes + [ Cask.caskroom.to_s ])
ohai "Successfully linked Alfred to homebrew-cask."
end
def self.unlink
return unless assert_installed
unless linked?
opoo "Alfred appears to be already unlinked. Updating defaults anyway."
end
odebug 'Unlinking Alfred scopes'
save_alfred_scopes(alfred_scopes.reject { |x| x == Cask.caskroom.to_s })
ohai "Successfully unlinked Alfred from homebrew-cask."
end
def self.status
return unless assert_installed
if linked?
ohai "Alfred is happily linked to homebrew-cask!"
else
ohai "Alfred is not linked to homebrew-cask."
end
if alfred_localprefs? and localprefs_scopes_files.size > 1
opoo "Multiple local preference files detected. 'brew cask alfred status' may be inaccurate."
end
end
def self.save_alfred_scopes(scopes)
alfred_preference(PRIMARY_SCOPES_KEY, %Q{(#{scopes.map { |s| "'#{s}'" }.join(',')})})
end
def self.alfred_version
begin
# reset the version every time when running under the test harness
# todo: I don't know the right way to detect that; using const_get
Cask.const_get(:FakeSystemCommand)
@alfred_version = nil
rescue StandardError => e
end
return @alfred_version if @alfred_version
v = alfred_primary_preference('version')
@alfred_version = begin
Gem::Version.new(v).to_s.to_f
rescue StandardError => e
0
end
end
def self.alfred_2_installed?
alfred_version >= 2.0
end
def self.alfred_localprefs?
alfred_version >= 2.4
end
def self.linked?
alfred_scopes.include?(Cask.caskroom.to_s)
end
# output looks like this:
# (
# "/some/path",
# "/other/path"
# )
#
# and we would like %w[/some/path /other/path]
SCOPE_REGEXP = /^\s*"(.*)",?$/
def self.alfred_scopes
scopes = alfred_preference(PRIMARY_SCOPES_KEY).split("\n").map do |line|
$1 if line.match(SCOPE_REGEXP)
end.compact
scopes.empty? ? DEFAULT_SCOPES : scopes
end
def self.localprefs_scopes_files
# local prefs file is used in Alfred 2.4 and above for Yosemite compatibility
prefs_path = alfred_primary_preference(LOCALPREFS_SYNCDIR_KEY).strip
Pathname.glob(Pathname.new(prefs_path + LOCALPREFS_SUBPATH).expand_path)
end
def self.alfred_preference(key, value=nil)
if alfred_localprefs? and key == PRIMARY_SCOPES_KEY
alfred_file_preference(localprefs_scopes_files, LOCALPREFS_SCOPES_KEY, value)
else
alfred_primary_preference(key, value)
end
end
def self.alfred_primary_preference(key, value=nil)
if value
odebug 'Writing Alfred primary preferences'
@system_command.run('/usr/bin/defaults', :args => ['write', PRIMARY_DOMAIN, key, value.to_s])
else
odebug 'Reading Alfred primary preferences'
@system_command.run('/usr/bin/defaults', :args => ['read', PRIMARY_DOMAIN, key]).stdout
end
end
def self.alfred_file_preference(files, key, value=nil)
unless files and files.length > 0
raise CaskError.new "Required 'files' argument empty"
end
Array(files).map do |file|
if value
odebug 'Writing Alfred local preferences'
@system_command.run('/usr/bin/defaults', :args => ['write', file, key, value.to_s])
else
odebug 'Reading Alfred local preferences'
@system_command.run('/usr/bin/defaults', :args => ['read', file, key]).stdout
end
# hack/limitation: if there happen to be multiple local preference
# files, we only return the value from the first one.
end.first
end
def self.usage
ohai 'brew cask alfred', <<-ALFREDHELP.undent
manages integration with Alfred; allows applications installed via
homebrew-cask to be launched by Alfred, by adding the Caskroom
directory to Alfred's search paths
subcommands:
status - reports whether Alfred is linked
link - adds Caskroom to alfred search paths
unlink - removes Caskroom from Alfred search paths
ALFREDHELP
end
end