From 3d3207bf5dbdc2b913878f86a1d80276b1cc1748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Mon, 24 Sep 2012 01:53:26 +1200 Subject: [PATCH 1/6] Add basic taps functionality; partial phinze/#12 support Instead of only listing `Taps/phinze-cask/Casks`, now list every taps that has a `Casks` directory. Might conflict with a few commands for the moment, works OK with `brew cask search`. --- lib/cask.rb | 26 +++++++++++++++++++------- lib/cask/cli/search.rb | 16 +++++++++++++++- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/lib/cask.rb b/lib/cask.rb index be5d77b7a..e4bfaa1ee 100644 --- a/lib/cask.rb +++ b/lib/cask.rb @@ -17,8 +17,8 @@ require 'cask/exceptions' require 'plist/parser' class Cask - def self.path - HOMEBREW_PREFIX.join("Library", "Taps", "phinze-cask", "Casks") + def self.tapspath + HOMEBREW_PREFIX.join "Library", "Taps" end def self.cellarpath @@ -26,12 +26,23 @@ class Cask end def self.all - cask_titles = path.entries.map(&:to_s).grep(/.rb$/).map { |p| p.to_s.split('.').first } - cask_titles.map { |c| self.load(c) } + cask_titles = Dir[tapspath.join("*", "Casks", "*.rb")] + cask_titles.map { |c| + # => "/usr/local/Library/Taps/example-tap/Casks/example.rb" + c.sub! /\.rb$/, '' + # => ".../example" + c = c.split("/").last 3 + # => ["example-tap", "Casks", "example"] + c.delete_at 1 + # => ["example-tap", "example"] + c = c.join "/" + # => "example-tap/example" + self.load c + c + } end def self.init - path.mkpath HOMEBREW_CACHE.mkpath HOME_APPS.mkpath end @@ -46,8 +57,9 @@ class Cask end def self.load(cask_title) - require path.join(cask_title) - const_get(cask_title.split('-').map(&:capitalize).join).new + path = tapspath.join cask_title.sub("/", "/Casks/") + require path + const_get(cask_title.split('/').last.split('-').map(&:capitalize).join).new end def self.title diff --git a/lib/cask/cli/search.rb b/lib/cask/cli/search.rb index abced7a01..ea16731c2 100644 --- a/lib/cask/cli/search.rb +++ b/lib/cask/cli/search.rb @@ -1,7 +1,21 @@ class Cask::CLI::Search def self.run(*arguments) search_term, *rest = *arguments - puts Cask.all.map(&:to_s).grep(/#{search_term}/).join("\n") + casks = {} + Cask.all.grep(/#{search_term}/).each { |c| + repo, name = c.split "/" + casks[name] ||= [] + casks[name].push repo + } + list = [] + casks.each { |name,repos| + if repos.length == 1 + list.push name + else + repos.each { |r| list.push [r,name].join "/" } + end + } + puts list.join "\n" end def self.help From 4a6e0b2513965ad07446e10719e2aa8e8bca3e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Mon, 24 Sep 2012 13:49:52 +1200 Subject: [PATCH 2/6] Sort search results --- lib/cask/cli/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cask/cli/search.rb b/lib/cask/cli/search.rb index ea16731c2..0e5a69f74 100644 --- a/lib/cask/cli/search.rb +++ b/lib/cask/cli/search.rb @@ -15,7 +15,7 @@ class Cask::CLI::Search repos.each { |r| list.push [r,name].join "/" } end } - puts list.join "\n" + puts list.sort.join "\n" end def self.help From 5b51542ccf43a2bbc1840eefeddd43baf8a2a3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Mon, 24 Sep 2012 14:05:34 +1200 Subject: [PATCH 3/6] Use puts_columns --- lib/cask/cli/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cask/cli/search.rb b/lib/cask/cli/search.rb index 0e5a69f74..06c5bb217 100644 --- a/lib/cask/cli/search.rb +++ b/lib/cask/cli/search.rb @@ -15,7 +15,7 @@ class Cask::CLI::Search repos.each { |r| list.push [r,name].join "/" } end } - puts list.sort.join "\n" + puts_columns list.sort.join "\n" end def self.help From 4de758bca3e518e92338ffabbfd6c539d4026bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Mon, 24 Sep 2012 15:47:00 +1200 Subject: [PATCH 4/6] Add tap support to `edit` and `list` Most notably, Cask.all returns an array of strings, not of Cask instances. This makes things easier, as well as faster, as there's no need to run map(&:to_s) everywhere anymore. self.path is a utility method which returns the path of the cask from its title. There's something subtle going in there: - If `cask_title` is fully qualified, e.g. "phinze-cask/alfred", it's straightforward. - If `cask_title` is only the name, e.g. "firefox-aurora", the name is matched from the full list (self.all) (which isn't sorted) and the first result is returned. Hence, self.path with only the name is not precise. There might be the possibility to apply heuristics to do a better match (prefer phinze-cask, or maybe installed casks?) but that's for another issue :-) self.nice_listing is another utility method used in `search` and `list`. It returns a list where unique casks don't have a prefix, and duplicates do. The prefix is the tap name. The list is then sorted. For an example or two, look at the first comment on phinze/#12. --- lib/cask.rb | 28 +++++++++++++++++++++++++--- lib/cask/cli/edit.rb | 4 ++-- lib/cask/cli/list.rb | 2 +- lib/cask/cli/search.rb | 15 +-------------- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/lib/cask.rb b/lib/cask.rb index e4bfaa1ee..740478420 100644 --- a/lib/cask.rb +++ b/lib/cask.rb @@ -41,6 +41,24 @@ class Cask c } end + + def self.nice_listing(cask_list) + casks = {} + cask_list.each { |c| + repo, name = c.split "/" + casks[name] ||= [] + casks[name].push repo + } + list = [] + casks.each { |name,repos| + if repos.length == 1 + list.push name + else + repos.each { |r| list.push [r,name].join "/" } + end + } + list.sort + end def self.init HOMEBREW_CACHE.mkpath @@ -53,12 +71,16 @@ class Cask def homepage; self.class.homepage; end def self.installed - self.all.select(&:installed?) + self.all.select { |c| load(c).installed? } + end + + def self.path(cask_title) + cask_title = all.grep(/#{cask_title}$/).first unless cask_title =~ /\// + tapspath.join(cask_title.sub("/", "/Casks/") + ".rb") unless cask_title.nil? end def self.load(cask_title) - path = tapspath.join cask_title.sub("/", "/Casks/") - require path + require path cask_title const_get(cask_title.split('/').last.split('-').map(&:capitalize).join).new end diff --git a/lib/cask/cli/edit.rb b/lib/cask/cli/edit.rb index bb9dd1db1..d794813c4 100644 --- a/lib/cask/cli/edit.rb +++ b/lib/cask/cli/edit.rb @@ -1,8 +1,8 @@ class Cask::CLI::Edit def self.run(*arguments) cask_name, *rest = *arguments - cask_path = Cask.path.join("#{cask_name}.rb") - raise CaskUnavailableError, cask_path.basename('.rb').to_s unless cask_path.file? + cask_path = Cask.path(cask_name) + raise CaskUnavailableError, cask_name + ".rb" if cask_path.nil? || !cask_path.file? exec_editor cask_path end diff --git a/lib/cask/cli/list.rb b/lib/cask/cli/list.rb index 1ff12d90a..be604c0e4 100644 --- a/lib/cask/cli/list.rb +++ b/lib/cask/cli/list.rb @@ -1,6 +1,6 @@ class Cask::CLI::List def self.run(*arguments) - puts Cask.installed.map(&:to_s).join("\n") + puts_columns Cask.nice_listing(Cask.installed) end def self.help diff --git a/lib/cask/cli/search.rb b/lib/cask/cli/search.rb index 06c5bb217..bf76a9aec 100644 --- a/lib/cask/cli/search.rb +++ b/lib/cask/cli/search.rb @@ -2,20 +2,7 @@ class Cask::CLI::Search def self.run(*arguments) search_term, *rest = *arguments casks = {} - Cask.all.grep(/#{search_term}/).each { |c| - repo, name = c.split "/" - casks[name] ||= [] - casks[name].push repo - } - list = [] - casks.each { |name,repos| - if repos.length == 1 - list.push name - else - repos.each { |r| list.push [r,name].join "/" } - end - } - puts_columns list.sort.join "\n" + puts_columns Cask.nice_listing(Cask.all.grep(/#{search_term}/)) end def self.help From 51e576061585d196f7de5139014008c2b5eea5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Mon, 24 Sep 2012 16:26:50 +1200 Subject: [PATCH 5/6] Allow wider definition for _zip? Some zip files have a different definition, e.g. Minecraft has: application/xml; charset=utf-8 compressed-encoding=application/zip; charset=binary; charset=binary Most other zips have: application/x-empty; compressed-encoding=application/zip; charset=binary; charset=binary But the result is the same. So now we test only for: compressed-encoding=application/zip; charset=binary; charset=binary --- lib/cask.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cask.rb b/lib/cask.rb index 740478420..74a8d97ea 100644 --- a/lib/cask.rb +++ b/lib/cask.rb @@ -199,7 +199,7 @@ class Cask def _zip?(path) output = `file -Izb #{path}` - output.chomp == 'application/x-empty compressed-encoding=application/zip; charset=binary; charset=binary' + output.chomp.include? 'compressed-encoding=application/zip; charset=binary; charset=binary' end def _tar_bzip?(path) From 96b192f26ba709eb0daff6db072de91cdbbb12ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Mon, 24 Sep 2012 16:47:45 +1200 Subject: [PATCH 6/6] Update README w/ info about taps --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 67a4eae8e..c1f80f19d 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,11 @@ together. The whole idea is to build a _community-maintained_ list of easily installable packages, so the community part is important! Every little bit counts. +# Taps + +You can add Casks to your existing (or new) taps: just create a directory named +`Casks` inside your tap, put your Casks there, and everything will just work. + # Alfred Integration I've been using Casks along with Alfred to great effect. Just add