add Cask::SubversionDownloadStrategy

abstract out module `Cask::DownloadStrategy`, add some commentary
This commit is contained in:
Roland Walker 2014-02-08 13:30:21 -05:00
parent a89a4ad218
commit b55f1804f0
8 changed files with 239 additions and 4 deletions

View File

@ -8,7 +8,11 @@ class Cask::Download
def perform
require 'software_spec'
cask = @cask
downloader = Cask::CurlDownloadStrategy.new(cask)
if cask.url.using == :svn
downloader = Cask::SubversionDownloadStrategy.new(cask)
else
downloader = Cask::CurlDownloadStrategy.new(cask)
end
downloaded_path = downloader.fetch
_check_sums(downloaded_path, cask.sums) unless cask.sums === 0

View File

@ -1,10 +1,17 @@
require 'cgi'
class Cask::CurlDownloadStrategy < CurlDownloadStrategy
# We abuse Homebrew's download strategies considerably here.
# * Our downloader instances only invoke the fetch method,
# ignoring stage and clear_cache.
# * Our overridden fetch methods are expected to return
# a value: the successfully downloaded file.
module Cask::DownloadStrategy
attr_reader :cask, :cask_url
def initialize(cask)
def initialize(cask, command=Cask::SystemCommand)
@cask = cask
@command = command
@cask_url = cask.url
super(
cask.title,
@ -14,6 +21,11 @@ class Cask::CurlDownloadStrategy < CurlDownloadStrategy
end
)
end
end
class Cask::CurlDownloadStrategy < CurlDownloadStrategy
include Cask::DownloadStrategy
def _fetch
odebug "Calling curl with args #{curl_args}"
@ -63,3 +75,74 @@ class Cask::CurlDownloadStrategy < CurlDownloadStrategy
end
end
end
class Cask::SubversionDownloadStrategy < SubversionDownloadStrategy
include Cask::DownloadStrategy
# super does not provide checks for already-existing downloads
def fetch
if tarball_path.exist?
puts "Already downloaded: #{tarball_path}"
else
super
compress
end
tarball_path
end
# This primary reason for redefining this method is the trust_cert
# option, controllable from the Cask definition. The rest of this
# method is similar to Homebrew's, but translated to local idiom.
def fetch_repo target, url, revision=cask_url.revision, ignore_externals=false
# Use "svn up" when the repository already exists locally.
# This saves on bandwidth and will have a similar effect to verifying the
# cache as it will make any changes to get the right revision.
svncommand = target.directory? ? 'up' : 'checkout'
args = [svncommand]
# SVN shipped with XCode 3.1.4 can't force a checkout.
args << '--force' unless MacOS.version == :leopard
if cask_url.trust_cert
args << '--trust-server-cert'
args << '--non-interactive'
end
args << url unless target.directory?
args << target
args << '-r' << revision if revision
args << '--ignore-externals' if ignore_externals
@command.run!('/usr/bin/svn',
:args => args,
:stderr => :silence)
end
def tarball_path
@tarball_path ||= cached_location.dirname.join(cached_location.basename.to_s + "-#{@cask.version}.tar")
end
private
# Seems nutty: we "download" the contents into a tape archive.
# Why?
# * A single file is tractable to the rest of the Cask toolchain,
# * An alternative would be to create a Directory container type.
# However, some type of file-serialization trick would still be
# needed in order to enable calculating a single checksum over
# a directory. So, in that alternative implementation, the
# special cases would propagate outside this class, including
# the use of tar or equivalent.
# * SubversionDownloadStrategy.cached_location is not versioned
# * tarball_path provides a needed return value for our overridden
# fetch method.
# * We can also take this private opportunity to strip files from
# the download which are protocol-specific.
def compress
Dir.chdir(cached_location) do
@command.run!('/usr/bin/tar', :args => ['-s/^\.//', '--exclude', '.svn', '-cf', Pathname.new(tarball_path), '--', '.'],
:stderr => :silent)
end
clear_cache
end
end

View File

@ -3,7 +3,7 @@ require 'forwardable'
class Cask::URL
FAKE_USER_AGENT = 'Chrome/32.0.1000.00'
attr_reader :uri, :cookies, :referer
attr_reader :using, :revision, :trust_cert, :uri, :cookies, :referer
extend Forwardable
def_delegators :uri, :path, :scheme, :to_s
@ -13,6 +13,9 @@ class Cask::URL
@user_agent = options[:user_agent]
@cookies = options[:cookies]
@referer = options[:referer]
@using = options[:using]
@revision = options[:revision]
@trust_cert = options[:trust_cert]
end
def user_agent

View File

@ -94,4 +94,121 @@ describe Cask::CurlDownloadStrategy do
shutup { downloader.fetch }
end
describe Cask::SubversionDownloadStrategy do
it 'recognizes the SVN download strategy' do
cask = Cask.load('svn-download-cask')
cask.url.using.must_equal :svn
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
downloader.must_respond_to(:fetch)
end
it 'properly assigns a name and Resource based on the cask' do
cask = Cask.load('svn-download-cask')
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
downloader.name.must_equal 'svn-download-cask'
downloader.resource.name.must_equal 'svn-download-cask'
downloader.resource.url.must_equal cask.url.to_s
downloader.resource.version.to_s.must_equal cask.version
end
it 'returns a tarball path on fetch' do
cask = Cask.load('svn-download-cask')
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
downloader.stubs(:fetch_repo)
downloader.stubs(:compress)
shutup { downloader.fetch }.must_equal downloader.tarball_path
end
it 'calls fetch_repo with default arguments for a simple Cask' do
cask = Cask.load('svn-download-cask')
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
downloader.stubs(:compress)
downloader.expects(:fetch_repo).with(
downloader.cached_location,
cask.url.to_s
)
shutup { downloader.fetch }.must_equal downloader.tarball_path
end
it 'calls svn with default arguments for a simple Cask' do
cask = Cask.load('svn-download-cask')
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
Cask::FakeSystemCommand.expects_command([
'/usr/bin/svn',
'checkout',
'--force',
cask.url.to_s,
downloader.cached_location,
])
downloader.stubs(:compress)
shutup { downloader.fetch }.must_equal downloader.tarball_path
end
it 'adds svn arguments for :trust_cert' do
cask = Cask.load('svn-download-trust-cask')
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
Cask::FakeSystemCommand.expects_command([
'/usr/bin/svn',
'checkout',
'--force',
'--trust-server-cert',
'--non-interactive',
cask.url.to_s,
downloader.cached_location,
])
downloader.stubs(:compress)
shutup { downloader.fetch }.must_equal downloader.tarball_path
end
it 'adds svn arguments for :revision' do
cask = Cask.load('svn-download-revision-cask')
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
Cask::FakeSystemCommand.expects_command([
'/usr/bin/svn',
'checkout',
'--force',
cask.url.to_s,
downloader.cached_location,
'-r',
'10',
])
downloader.stubs(:compress)
shutup { downloader.fetch }.must_equal downloader.tarball_path
end
it 'runs tar to serialize svn downloads' do
cask = Cask.load('svn-download-cask')
downloader = Cask::SubversionDownloadStrategy.new(cask, Cask::FakeSystemCommand)
# special mocking required for tar to have something to work with
def downloader.fetch_repo(target, url, revision=nil, ignore_externals=false)
target.mkpath
end
Cask::FakeSystemCommand.expects_command([
'/usr/bin/tar',
'-s/^\\.//',
'--exclude',
'.svn',
'-cf',
downloader.tarball_path,
'--',
'.',
])
shutup { downloader.fetch }.must_equal downloader.tarball_path
end
end
# does not work yet, for numerous reasons
# it 'creates a tarball matching the expected checksum' do
# cask = Cask.load('svn-download-check-cask')
# downloader = Cask::SubversionDownloadStrategy.new(cask)
# # special mocking required for tar to have something to work with
# def downloader.fetch_repo(target, url, revision=nil, ignore_externals=false)
# target.mkpath
# FileUtils.touch(target.join('empty_file'))
# end
# shutup { downloader.fetch }.must_equal downloader.tarball_path
# d = Cask::Download.new(cask)
# d._check_sums(downloader.tarball_path, cask.sums)
# end
end

View File

@ -0,0 +1,7 @@
class SvnDownloadCask < TestCask
url 'http://example.com/trunk/projectdir/subdir', :using => :svn
homepage 'http://example.com/'
version '1.2.3'
sha1 '39f3444fcb5d49618c2d62dd7b34304ea5f97a3a'
link 'TestCask.app'
end

View File

@ -0,0 +1,7 @@
class SvnDownloadCheckCask < TestCask
url 'http://example.com/trunk/projectdir/subdir', :using => :svn
homepage 'http://example.com/'
version '1.2.3'
sha1 '39f3444fcb5d49618c2d62dd7b34304ea5f97a3a'
link 'TestCask.app'
end

View File

@ -0,0 +1,7 @@
class SvnDownloadRevisionCask < TestCask
url 'http://example.com/trunk/projectdir/subdir', :using => :svn, :revision => '10'
homepage 'http://example.com/'
version '1.2.3'
sha1 '39f3444fcb5d49618c2d62dd7b34304ea5f97a3a'
link 'TestCask.app'
end

View File

@ -0,0 +1,7 @@
class SvnDownloadTrustCask < TestCask
url 'http://example.com/trunk/projectdir/subdir', :using => :svn, :trust_cert => true
homepage 'http://example.com/'
version '1.2.3'
sha1 '39f3444fcb5d49618c2d62dd7b34304ea5f97a3a'
link 'TestCask.app'
end