Merge pull request #9480 from caskroom/sprout-hbc-cask-object-from-namespace

core: [refactor] separate Hbc::Cask from Hbc
This commit is contained in:
Roland Walker 2015-02-07 19:06:51 -05:00
commit fa4f23715b
21 changed files with 163 additions and 156 deletions

View File

@ -1,11 +1,12 @@
HOMEBREW_CACHE_CASKS = HOMEBREW_CACHE.join('Casks')
class Hbc; end
module Hbc; end
require 'hbc/extend'
require 'hbc/artifact'
require 'hbc/audit'
require 'hbc/auditor'
require 'hbc/cask'
require 'hbc/without_source'
require 'hbc/checkable'
require 'hbc/cli'
@ -14,7 +15,6 @@ require 'hbc/caveats'
require 'hbc/container'
require 'hbc/download'
require 'hbc/download_strategy'
require 'hbc/dsl'
require 'hbc/exceptions'
require 'hbc/fetcher'
require 'hbc/hardware'
@ -39,8 +39,7 @@ require 'hbc/version'
require 'vendor/plist'
class Hbc
include Hbc::DSL
module Hbc
include Hbc::Locations
include Hbc::Scopes
include Hbc::Options
@ -87,89 +86,4 @@ class Hbc
cask.dumpcask
cask
end
def self.token
# todo removeme: prepending KlassPrefix is transitional as we move away from representing Casks as classes
self.name.sub(/^KlassPrefix/,'').gsub(/([a-zA-Z\d])([A-Z])/,'\1-\2').gsub(/([a-zA-Z\d])([A-Z])/,'\1-\2').downcase
end
def self.nowstamp_metadata_path(container_path)
@timenow ||= Time.now.gmtime
if container_path.respond_to?(:join)
precision = 3
timestamp = @timenow.strftime('%Y%m%d%H%M%S')
fraction = ("%.#{precision}f" % (@timenow.to_f - @timenow.to_i))[1..-1]
timestamp.concat(fraction)
container_path.join(timestamp)
end
end
attr_reader :token, :sourcefile_path
def initialize(sourcefile_path=nil)
@sourcefile_path = sourcefile_path
@token = self.class.token
end
def caskroom_path
self.class.caskroom.join(token)
end
# todo: move to staged.rb ?
def staged_path
cask_version = version ? version : :unknown
caskroom_path.join(cask_version.to_s)
end
def metadata_master_container_path
caskroom_path.join(self.class.metadata_subdir)
end
def metadata_versioned_container_path
cask_version = version ? version : :unknown
metadata_master_container_path.join(cask_version.to_s)
end
def metadata_path(timestamp=:latest, create=false)
return nil unless metadata_versioned_container_path.respond_to?(:join)
if create and timestamp == :latest
raise Hbc::CaskError.new('Cannot create metadata path when timestamp is :latest')
end
if timestamp == :latest
path = Pathname.glob(metadata_versioned_container_path.join('*')).sort.last
elsif timestamp == :now
path = self.class.nowstamp_metadata_path(metadata_versioned_container_path)
else
path = metadata_versioned_container_path.join(timestamp)
end
if create
odebug "Creating metadata directory #{path}"
FileUtils.mkdir_p path
end
path
end
def metadata_subdir(leaf, timestamp=:latest, create=false)
if create and timestamp == :latest
raise Hbc::CaskError.new('Cannot create metadata subdir when timestamp is :latest')
end
unless leaf.respond_to?(:length) and leaf.length > 0
raise Hbc::CaskError.new('Cannot create metadata subdir for empty leaf')
end
parent = metadata_path(timestamp, create)
return nil unless parent.respond_to?(:join)
subdir = parent.join(leaf)
if create
odebug "Creating metadata subdirectory #{subdir}"
FileUtils.mkdir_p subdir
end
subdir
end
def installed?
staged_path.exist?
end
def to_s
@token
end
end

109
lib/hbc/cask.rb Normal file
View File

@ -0,0 +1,109 @@
require 'hbc/dsl'
class Hbc::Cask
include Hbc::DSL
def self.token
# todo removeme: prepending KlassPrefix is transitional as we move away from representing Casks as classes
self.name.sub(/^KlassPrefix/,'').gsub(/([a-zA-Z\d])([A-Z])/,'\1-\2').gsub(/([a-zA-Z\d])([A-Z])/,'\1-\2').downcase
end
attr_reader :token, :sourcefile_path
def initialize(sourcefile_path=nil)
@sourcefile_path = sourcefile_path
@token = self.class.token
end
def caskroom_path
Hbc.caskroom.join(token)
end
# todo: move to staged.rb ?
def staged_path
cask_version = version ? version : :unknown
caskroom_path.join(cask_version.to_s)
end
METADATA_SUBDIR = '.metadata'
def metadata_master_container_path
caskroom_path.join(METADATA_SUBDIR)
end
def metadata_versioned_container_path
cask_version = version ? version : :unknown
metadata_master_container_path.join(cask_version.to_s)
end
def metadata_path(timestamp=:latest, create=false)
return nil unless metadata_versioned_container_path.respond_to?(:join)
if create and timestamp == :latest
raise Hbc::CaskError.new('Cannot create metadata path when timestamp is :latest')
end
if timestamp == :latest
path = Pathname.glob(metadata_versioned_container_path.join('*')).sort.last
elsif timestamp == :now
path = Hbc::Utils.nowstamp_metadata_path(metadata_versioned_container_path)
else
path = metadata_versioned_container_path.join(timestamp)
end
if create
odebug "Creating metadata directory #{path}"
FileUtils.mkdir_p path
end
path
end
def metadata_subdir(leaf, timestamp=:latest, create=false)
if create and timestamp == :latest
raise Hbc::CaskError.new('Cannot create metadata subdir when timestamp is :latest')
end
unless leaf.respond_to?(:length) and leaf.length > 0
raise Hbc::CaskError.new('Cannot create metadata subdir for empty leaf')
end
parent = metadata_path(timestamp, create)
return nil unless parent.respond_to?(:join)
subdir = parent.join(leaf)
if create
odebug "Creating metadata subdirectory #{subdir}"
FileUtils.mkdir_p subdir
end
subdir
end
def installed?
staged_path.exist?
end
def to_s
@token
end
def dumpcask
if Hbc.respond_to?(:debug) and Hbc.debug
odebug "Cask instance dumps in YAML:"
odebug "Cask instance toplevel:", self.to_yaml
[
:full_name,
:homepage,
:url,
:appcast,
:version,
:license,
:tags,
:sha256,
:artifacts,
:caveats,
:depends_on,
:conflicts_with,
:container,
:gpg,
:accessibility_access,
].each do |method|
printable_method = method.to_s
printable_method = "name" if printable_method == "full_name"
odebug "Cask instance method '#{printable_method}':", self.send(method).to_yaml
end
end
end
end

View File

@ -38,7 +38,7 @@ PURPOSE
def self.github_info(cask)
cask_token = cask.token
cask_token = cask.class.all_tokens.detect { |t| t.split("/").last == cask_token } unless cask_token =~ /\//
cask_token = Hbc.all_tokens.detect { |t| t.split("/").last == cask_token } unless cask_token =~ /\//
return nil unless cask_token.respond_to?(:length) and cask_token.length > 0
path_elements = cask_token.split '/'
if path_elements.count == 2

View File

@ -4,10 +4,6 @@ module Hbc::Locations
end
module ClassMethods
def metadata_subdir
'.metadata'
end
def caskroom
@@caskroom ||= Pathname('/opt/homebrew-cask/Caskroom')
end

View File

@ -51,7 +51,7 @@ class Hbc::Source::PathBase
is_test = ! $2.nil?
header_token = $4
dsl_version = Gem::Version.new(dsl_version_string.gsub('_','.'))
superclass_name = is_test ? 'TestHbc' : 'Hbc'
superclass_name = is_test ? 'Hbc::TestCask' : 'Hbc::Cask'
cask_contents.sub!(%r{\A[^\n]+\n}, "class #{cask_class_name} < #{superclass_name}\n")
# todo the minimum DSL version should be defined globally elsewhere
minimum_dsl_version = Gem::Version.new('1.0')

View File

@ -76,33 +76,6 @@ def puts_columns(items, star_items=[])
end
module Hbc::Utils
def dumpcask
if Hbc.respond_to?(:debug) and Hbc.debug
odebug "Cask instance dumps in YAML:"
odebug "Cask instance toplevel:", self.to_yaml
[
:full_name,
:homepage,
:url,
:appcast,
:version,
:license,
:tags,
:sha256,
:artifacts,
:caveats,
:depends_on,
:conflicts_with,
:container,
:gpg,
:accessibility_access,
].each do |method|
printable_method = method.to_s
printable_method = "name" if printable_method == "full_name"
odebug "Cask instance method '#{printable_method}':", self.send(method).to_yaml
end
end
end
def self.which(cmd, path=ENV['PATH'])
unless File.basename(cmd) == cmd.to_s
@ -253,4 +226,15 @@ module Hbc::Utils
ensure
trap('INT', std_trap)
end
def self.nowstamp_metadata_path(container_path)
@timenow ||= Time.now.gmtime
if container_path.respond_to?(:join)
precision = 3
timestamp = @timenow.strftime('%Y%m%d%H%M%S')
fraction = ("%.#{precision}f" % (@timenow.to_f - @timenow.to_i))[1..-1]
timestamp.concat(fraction)
container_path.join(timestamp)
end
end
end

View File

@ -1,4 +1,4 @@
class Hbc::WithoutSource < Hbc
class Hbc::WithoutSource < Hbc::Cask
def staged_path
caskroom_path.children.first
end

View File

@ -1,4 +1,4 @@
class Hbc; end
module Hbc; end
# raised by safe_system in utils.rb
class Hbc::ErrorDuringExecution < RuntimeError

View File

@ -3,20 +3,20 @@ require 'spec_helper'
describe Hbc::Audit do
describe "result" do
it "is 'failed' if there are have been any errors added" do
audit = Hbc::Audit.new(Hbc.new)
audit = Hbc::Audit.new(Hbc::Cask.new)
audit.add_error 'bad'
audit.add_warning 'eh'
expect(audit.result).to match(/failed/)
end
it "is 'warning' if there are no errors, but there are warnings" do
audit = Hbc::Audit.new(Hbc.new)
audit = Hbc::Audit.new(Hbc::Cask.new)
audit.add_warning 'eh'
expect(audit.result).to match(/warning/)
end
it "is 'passed' if there are no errors or warning" do
audit = Hbc::Audit.new(Hbc.new)
audit = Hbc::Audit.new(Hbc::Cask.new)
expect(audit.result).to match(/passed/)
end
end
@ -73,7 +73,7 @@ describe Hbc::Audit do
download = double()
download.expects(:perform).raises(StandardError.new(error_message))
audit = Hbc::Audit.new(Hbc.new)
audit = Hbc::Audit.new(Hbc::Cask.new)
audit.run!(download)
expect(audit.errors).to include(/#{error_message}/)
end

View File

@ -4,7 +4,7 @@ describe 'download strategies' do
let(:url) { 'http://example.com/cask.dmg' }
let(:url_options) { Hash.new }
let(:cask) {
class_double(Hbc,
class_double(Hbc::Cask,
:token => 'some-cask',
:url => Hbc::URL.new(url, url_options),
:version => '1.2.3.4'

View File

@ -17,7 +17,9 @@ $:.push(project_root.join('lib').to_s)
require 'hbc'
class TestHbc < Hbc; end
module Hbc
class TestCask < Cask; end
end
# override Homebrew locations
Hbc.homebrew_prefix = Pathname.new(TEST_TMPDIR).join('prefix')

View File

@ -1,7 +1,7 @@
require 'test_helper'
describe "Casks" do
Hbc.all.reject {|c| c.is_a?(TestHbc) }.each do |cask|
Hbc.all.reject {|c| c.is_a?(Hbc::TestCask) }.each do |cask|
describe "#{cask}" do
it "passes audit" do
audit = Hbc::Audit.new(cask)

View File

@ -33,7 +33,7 @@ describe Hbc::Artifact::App do
end
it "works with an application in a subdir" do
AltSubDirCask = Class.new(Hbc)
AltSubDirCask = Class.new(Hbc::Cask)
AltSubDirCask.class_eval do
url TestHelper.local_binary_url('caffeine.zip')
homepage 'http://example.com/local-caffeine'

View File

@ -19,7 +19,7 @@ describe Hbc::Artifact::App do
end
it "works with an application in a subdir" do
SubDirCask = Class.new(Hbc)
SubDirCask = Class.new(Hbc::Cask)
SubDirCask.class_eval do
url TestHelper.local_binary_url('caffeine.zip')
homepage 'http://example.com/local-caffeine'

View File

@ -6,7 +6,7 @@ describe Hbc::Artifact::PostflightBlock do
called = false
yielded_arg = nil
CaskWithPostflight = Class.new(Hbc)
CaskWithPostflight = Class.new(Hbc::Cask)
CaskWithPostflight.class_eval do
postflight do |c|
called = true
@ -27,7 +27,7 @@ describe Hbc::Artifact::PostflightBlock do
called = false
yielded_arg = nil
CaskWithUninstallPostflight = Class.new(Hbc)
CaskWithUninstallPostflight = Class.new(Hbc::Cask)
CaskWithUninstallPostflight.class_eval do
uninstall_postflight do |c|
called = true

View File

@ -6,7 +6,7 @@ describe Hbc::Artifact::PreflightBlock do
called = false
yielded_arg = nil
CaskWithPreflight = Class.new(Hbc)
CaskWithPreflight = Class.new(Hbc::Cask)
CaskWithPreflight.class_eval do
preflight do |c|
called = true
@ -27,7 +27,7 @@ describe Hbc::Artifact::PreflightBlock do
called = false
yielded_arg = nil
CaskWithUninstallPreflight = Class.new(Hbc)
CaskWithUninstallPreflight = Class.new(Hbc::Cask)
CaskWithUninstallPreflight.class_eval do
uninstall_preflight do |c|
called = true

View File

@ -20,7 +20,7 @@ describe Hbc::Artifact::App do
end
it "works with an application in a subdir" do
AltSubDirTwoAppsCask = Class.new(Hbc)
AltSubDirTwoAppsCask = Class.new(Hbc::Cask)
AltSubDirTwoAppsCask.class_eval do
url TestHelper.local_binary_url('caffeine.zip')
homepage 'http://example.com/local-caffeine'

View File

@ -2,7 +2,7 @@ require 'test_helper'
describe Hbc::Container::Naked do
it "saves files with spaces in them from uris with encoded spaces" do
SpaceyCask = Class.new(Hbc)
SpaceyCask = Class.new(Hbc::Cask)
SpaceyCask.class_eval do
url 'http://example.com/kevin%20spacey.pkg'
version '1.2'

View File

@ -9,7 +9,7 @@ describe Hbc::DSL do
end
describe "when a Cask includes an unknown method" do
UnexpectedMethodCask = Class.new(Hbc)
UnexpectedMethodCask = Class.new(Hbc::Cask)
attempt_unknown_method = nil
before do
@ -71,7 +71,7 @@ describe Hbc::DSL do
describe "name stanza" do
it "lets you set the full name via a name stanza" do
NameCask = Class.new(Hbc)
NameCask = Class.new(Hbc::Cask)
NameCask.class_eval do
name 'Proper Name'
end
@ -82,7 +82,7 @@ describe Hbc::DSL do
end
it "Accepts an array value to the name stanza" do
ArrayNameCask = Class.new(Hbc)
ArrayNameCask = Class.new(Hbc::Cask)
ArrayNameCask.class_eval do
name ['Proper Name', 'Alternate Name']
end
@ -94,7 +94,7 @@ describe Hbc::DSL do
end
it "Accepts multiple name stanzas" do
MultiNameCask = Class.new(Hbc)
MultiNameCask = Class.new(Hbc::Cask)
MultiNameCask.class_eval do
name 'Proper Name'
name 'Alternate Name'
@ -109,7 +109,7 @@ describe Hbc::DSL do
describe "sha256 stanza" do
it "lets you set checksum via sha256" do
ChecksumCask = Class.new(Hbc)
ChecksumCask = Class.new(Hbc::Cask)
ChecksumCask.class_eval do
sha256 'imasha2'
end
@ -120,7 +120,7 @@ describe Hbc::DSL do
describe "app stanza" do
it "allows you to specify app stanzas" do
CaskWithApps = Class.new(Hbc)
CaskWithApps = Class.new(Hbc::Cask)
CaskWithApps.class_eval do
app 'Foo.app'
app 'Bar.app'
@ -131,7 +131,7 @@ describe Hbc::DSL do
end
it "allow app stanzas to be empty" do
CaskWithNoApps = Class.new(Hbc)
CaskWithNoApps = Class.new(Hbc::Cask)
instance = CaskWithNoApps.new
Array(instance.artifacts[:app]).must_equal %w[]
@ -140,13 +140,13 @@ describe Hbc::DSL do
describe "caveats stanza" do
it "allows caveats to be specified via a method define" do
PlainCask = Class.new(Hbc)
PlainCask = Class.new(Hbc::Cask)
instance = PlainCask.new
instance.caveats.must_be :empty?
CaskWithCaveats = Class.new(Hbc)
CaskWithCaveats = Class.new(Hbc::Cask)
CaskWithCaveats.class_eval do
def caveats; <<-EOS.undent
When you install this Cask, you probably want to know this.
@ -162,7 +162,7 @@ describe Hbc::DSL do
describe "pkg stanza" do
it "allows installable pkgs to be specified" do
CaskWithPkgs = Class.new(Hbc)
CaskWithPkgs = Class.new(Hbc::Cask)
CaskWithPkgs.class_eval do
pkg 'Foo.pkg'
pkg 'Bar.pkg'

View File

@ -4,7 +4,7 @@ describe "Cask" do
describe "load" do
it "returns an instance of the Cask for the given token" do
c = Hbc.load("adium")
c.must_be_kind_of(Hbc)
c.must_be_kind_of(Hbc::Cask)
c.must_be_instance_of(KlassPrefixAdium)
end
@ -17,7 +17,7 @@ describe "Cask" do
end
location = File.expand_path('./Casks/dia.rb')
c = Hbc.load(location)
c.must_be_kind_of(Hbc)
c.must_be_kind_of(Hbc::Cask)
c.must_be_instance_of(KlassPrefixDia)
Object.class_eval{remove_const :KlassPrefixDia}
end
@ -31,7 +31,7 @@ describe "Cask" do
c = shutup do
Hbc.load(url)
end
c.must_be_kind_of(Hbc)
c.must_be_kind_of(Hbc::Cask)
c.must_be_instance_of(KlassPrefixDia)
Object.class_eval{remove_const :KlassPrefixDia}
end
@ -51,7 +51,7 @@ describe "Cask" do
rescue
end
c = Hbc.load("./Casks/bbedit.rb")
c.must_be_kind_of(Hbc)
c.must_be_kind_of(Hbc::Cask)
c.must_be_instance_of(KlassPrefixBbedit)
Object.class_eval{remove_const :KlassPrefixBbedit}
end
@ -78,12 +78,12 @@ describe "Cask" do
describe "token" do
it "converts a class constant to a token-style dashed string" do
KlassPrefixPascalCasedConstant = Class.new(Hbc)
KlassPrefixPascalCasedConstant = Class.new(Hbc::Cask)
KlassPrefixPascalCasedConstant.token.must_equal 'pascal-cased-constant'
end
it "properly dasherizes constants with single letters in the middle" do
KlassPrefixGamesXChange = Class.new(Hbc)
KlassPrefixGamesXChange = Class.new(Hbc::Cask)
KlassPrefixGamesXChange.token.must_equal 'games-x-change'
end
end

View File

@ -134,7 +134,9 @@ FileUtils.mkdir_p Hbc.homebrew_prefix.join('bin')
FileUtils.ln_s project_root, taps_dest.join('homebrew-cask')
# Common superclass for test Casks for when we need to filter them out
class TestHbc < Hbc; end
module Hbc
class TestCask < Cask; end
end
# jack in some optional utilities
FileUtils.ln_s '/usr/local/bin/cabextract', Hbc.homebrew_prefix.join('bin/cabextract')