Merge pull request #4585 from reitermarkus/refactor-download-strategies

Refactor download strategies.
This commit is contained in:
Markus Reiter 2018-08-02 07:16:27 +02:00 committed by GitHub
commit efd743a50d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 43 deletions

View File

@ -14,14 +14,13 @@ class AbstractDownloadStrategy
end end
end end
attr_reader :meta, :name, :version, :resource attr_reader :meta, :name, :version
attr_reader :shutup attr_reader :shutup
def initialize(name, resource) def initialize(name, version, resource)
@name = name @name = name
@resource = resource
@url = resource.url @url = resource.url
@version = resource.version @version = version
@meta = resource.specs @meta = resource.specs
@shutup = false @shutup = false
extend Pourable if meta[:bottle] extend Pourable if meta[:bottle]
@ -91,7 +90,7 @@ end
class VCSDownloadStrategy < AbstractDownloadStrategy class VCSDownloadStrategy < AbstractDownloadStrategy
REF_TYPES = [:tag, :branch, :revisions, :revision].freeze REF_TYPES = [:tag, :branch, :revisions, :revision].freeze
def initialize(name, resource) def initialize(name, version, resource)
super super
@ref_type, @ref = extract_ref(meta) @ref_type, @ref = extract_ref(meta)
@revision = meta[:revision] @revision = meta[:revision]
@ -137,7 +136,9 @@ class VCSDownloadStrategy < AbstractDownloadStrategy
@clone @clone
end end
delegate head?: :version def head?
version.respond_to?(:head?) && version.head?
end
# Return last commit's unique identifier for the repository. # Return last commit's unique identifier for the repository.
# Return most recent modified timestamp unless overridden. # Return most recent modified timestamp unless overridden.
@ -208,7 +209,7 @@ end
class CurlDownloadStrategy < AbstractFileDownloadStrategy class CurlDownloadStrategy < AbstractFileDownloadStrategy
attr_reader :mirrors, :tarball_path, :temporary_path attr_reader :mirrors, :tarball_path, :temporary_path
def initialize(name, resource) def initialize(name, version, resource)
super super
@mirrors = resource.mirrors.dup @mirrors = resource.mirrors.dup
@tarball_path = HOMEBREW_CACHE/"#{name}-#{version}#{ext}" @tarball_path = HOMEBREW_CACHE/"#{name}-#{version}#{ext}"
@ -255,6 +256,8 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
ohai "Downloading from #{url}" ohai "Downloading from #{url}"
end end
temporary_path.dirname.mkpath
curl_download resolved_url(url), to: temporary_path curl_download resolved_url(url), to: temporary_path
end end
@ -386,7 +389,7 @@ class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy
require "utils/formatter" require "utils/formatter"
require "utils/github" require "utils/github"
def initialize(name, resource) def initialize(name, version, resource)
super super
parse_url_pattern parse_url_pattern
set_github_token set_github_token
@ -492,7 +495,7 @@ end
class ScpDownloadStrategy < AbstractFileDownloadStrategy class ScpDownloadStrategy < AbstractFileDownloadStrategy
attr_reader :tarball_path, :temporary_path attr_reader :tarball_path, :temporary_path
def initialize(name, resource) def initialize(name, version, resource)
super super
@tarball_path = HOMEBREW_CACHE/"#{name}-#{version}#{ext}" @tarball_path = HOMEBREW_CACHE/"#{name}-#{version}#{ext}"
@temporary_path = Pathname.new("#{cached_location}.incomplete") @temporary_path = Pathname.new("#{cached_location}.incomplete")
@ -543,7 +546,7 @@ class ScpDownloadStrategy < AbstractFileDownloadStrategy
end end
class SubversionDownloadStrategy < VCSDownloadStrategy class SubversionDownloadStrategy < VCSDownloadStrategy
def initialize(name, resource) def initialize(name, version, resource)
super super
@url = @url.sub("svn+http://", "") @url = @url.sub("svn+http://", "")
end end
@ -628,7 +631,7 @@ class GitDownloadStrategy < VCSDownloadStrategy
%r{http://llvm\.org}, %r{http://llvm\.org},
].freeze ].freeze
def initialize(name, resource) def initialize(name, version, resource)
super super
@ref_type ||= :branch @ref_type ||= :branch
@ref ||= "master" @ref ||= "master"
@ -800,7 +803,7 @@ class GitDownloadStrategy < VCSDownloadStrategy
end end
class GitHubGitDownloadStrategy < GitDownloadStrategy class GitHubGitDownloadStrategy < GitDownloadStrategy
def initialize(name, resource) def initialize(name, version, resource)
super super
return unless %r{^https?://github\.com/(?<user>[^/]+)/(?<repo>[^/]+)\.git$} =~ @url return unless %r{^https?://github\.com/(?<user>[^/]+)/(?<repo>[^/]+)\.git$} =~ @url
@ -854,7 +857,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy
end end
class CVSDownloadStrategy < VCSDownloadStrategy class CVSDownloadStrategy < VCSDownloadStrategy
def initialize(name, resource) def initialize(name, version, resource)
super super
@url = @url.sub(%r{^cvs://}, "") @url = @url.sub(%r{^cvs://}, "")
@ -924,7 +927,7 @@ class CVSDownloadStrategy < VCSDownloadStrategy
end end
class MercurialDownloadStrategy < VCSDownloadStrategy class MercurialDownloadStrategy < VCSDownloadStrategy
def initialize(name, resource) def initialize(name, version, resource)
super super
@url = @url.sub(%r{^hg://}, "") @url = @url.sub(%r{^hg://}, "")
end end
@ -980,7 +983,7 @@ class MercurialDownloadStrategy < VCSDownloadStrategy
end end
class BazaarDownloadStrategy < VCSDownloadStrategy class BazaarDownloadStrategy < VCSDownloadStrategy
def initialize(name, resource) def initialize(name, version, resource)
super super
@url.sub!(%r{^bzr://}, "") @url.sub!(%r{^bzr://}, "")
ENV["BZR_HOME"] = HOMEBREW_TEMP ENV["BZR_HOME"] = HOMEBREW_TEMP
@ -1031,7 +1034,7 @@ class BazaarDownloadStrategy < VCSDownloadStrategy
end end
class FossilDownloadStrategy < VCSDownloadStrategy class FossilDownloadStrategy < VCSDownloadStrategy
def initialize(name, resource) def initialize(name, version, resource)
super super
@url = @url.sub(%r{^fossil://}, "") @url = @url.sub(%r{^fossil://}, "")
end end

View File

@ -105,7 +105,7 @@ module Formulary
formula_name = File.basename(bottle_name)[/(.+)-/, 1] formula_name = File.basename(bottle_name)[/(.+)-/, 1]
resource = Resource.new(formula_name) { url bottle_name } resource = Resource.new(formula_name) { url bottle_name }
resource.specs[:bottle] = true resource.specs[:bottle] = true
downloader = CurlDownloadStrategy.new resource.name, resource downloader = resource.downloader
cached = downloader.cached_location.exist? cached = downloader.cached_location.exist?
downloader.fetch downloader.fetch
ohai "Pouring the cached bottle" if cached ohai "Pouring the cached bottle" if cached

View File

@ -30,10 +30,6 @@ class Resource
@resource.specs @resource.specs
end end
def version
@resource.version
end
def mirrors def mirrors
@resource.mirrors @resource.mirrors
end end
@ -57,7 +53,7 @@ class Resource
end end
def downloader def downloader
download_strategy.new(download_name, Download.new(self)) download_strategy.new(download_name, version, Download.new(self))
end end
# Removes /s from resource names; this allows go package names # Removes /s from resource names; this allows go package names
@ -68,7 +64,9 @@ class Resource
end end
def download_name def download_name
name.nil? ? owner.name : "#{owner.name}--#{escaped_name}" return owner.name if name.nil?
return escaped_name if owner.nil?
"#{owner.name}--#{escaped_name}"
end end
def cached_download def cached_download

View File

@ -1,11 +1,12 @@
require "download_strategy" require "download_strategy"
describe AbstractDownloadStrategy do describe AbstractDownloadStrategy do
subject { described_class.new(name, resource) } subject { described_class.new(name, version, resource) }
let(:specs) { {} } let(:specs) { {} }
let(:name) { "foo" } let(:name) { "foo" }
let(:url) { "http://example.com/foo.tar.gz" } let(:url) { "http://example.com/foo.tar.gz" }
let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: specs, version: nil) } let(:resource) { double(Resource, url: url, mirrors: [], specs: specs, version: nil) }
let(:args) { %w[foo bar baz] } let(:args) { %w[foo bar baz] }
@ -35,22 +36,24 @@ end
describe VCSDownloadStrategy do describe VCSDownloadStrategy do
let(:url) { "http://example.com/bar" } let(:url) { "http://example.com/bar" }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}, version: nil) } let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}) }
describe "#cached_location" do describe "#cached_location" do
it "returns the path of the cached resource" do it "returns the path of the cached resource" do
allow_any_instance_of(described_class).to receive(:cache_tag).and_return("foo") allow_any_instance_of(described_class).to receive(:cache_tag).and_return("foo")
downloader = described_class.new("baz", resource) downloader = described_class.new("baz", version, resource)
expect(downloader.cached_location).to eq(HOMEBREW_CACHE/"baz--foo") expect(downloader.cached_location).to eq(HOMEBREW_CACHE/"baz--foo")
end end
end end
end end
describe GitHubPrivateRepositoryDownloadStrategy do describe GitHubPrivateRepositoryDownloadStrategy do
subject { described_class.new("foo", resource) } subject { described_class.new("foo", version, resource) }
let(:url) { "https://github.com/owner/repo/archive/1.1.5.tar.gz" } let(:url) { "https://github.com/owner/repo/archive/1.1.5.tar.gz" }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}, version: nil) } let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}) }
before do before do
ENV["HOMEBREW_GITHUB_API_TOKEN"] = "token" ENV["HOMEBREW_GITHUB_API_TOKEN"] = "token"
@ -71,10 +74,11 @@ describe GitHubPrivateRepositoryDownloadStrategy do
end end
describe GitHubPrivateRepositoryReleaseDownloadStrategy do describe GitHubPrivateRepositoryReleaseDownloadStrategy do
subject { described_class.new("foo", resource) } subject { described_class.new("foo", version, resource) }
let(:url) { "https://github.com/owner/repo/releases/download/tag/foo_v0.1.0_darwin_amd64.tar.gz" } let(:url) { "https://github.com/owner/repo/releases/download/tag/foo_v0.1.0_darwin_amd64.tar.gz" }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}, version: nil) } let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}) }
before do before do
ENV["HOMEBREW_GITHUB_API_TOKEN"] = "token" ENV["HOMEBREW_GITHUB_API_TOKEN"] = "token"
@ -122,11 +126,12 @@ describe GitHubPrivateRepositoryReleaseDownloadStrategy do
end end
describe GitHubGitDownloadStrategy do describe GitHubGitDownloadStrategy do
subject { described_class.new(name, resource) } subject { described_class.new(name, version, resource) }
let(:name) { "brew" } let(:name) { "brew" }
let(:url) { "https://github.com/homebrew/brew.git" } let(:url) { "https://github.com/homebrew/brew.git" }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}, version: nil) } let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}) }
it "parses the URL and sets the corresponding instance variables" do it "parses the URL and sets the corresponding instance variables" do
expect(subject.instance_variable_get(:@user)).to eq("homebrew") expect(subject.instance_variable_get(:@user)).to eq("homebrew")
@ -135,11 +140,12 @@ describe GitHubGitDownloadStrategy do
end end
describe GitDownloadStrategy do describe GitDownloadStrategy do
subject { described_class.new(name, resource) } subject { described_class.new(name, version, resource) }
let(:name) { "baz" } let(:name) { "baz" }
let(:url) { "https://github.com/homebrew/foo" } let(:url) { "https://github.com/homebrew/foo" }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}, version: nil) } let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}) }
let(:cached_location) { subject.cached_location } let(:cached_location) { subject.cached_location }
before do before do
@ -202,14 +208,15 @@ describe GitDownloadStrategy do
end end
describe S3DownloadStrategy do describe S3DownloadStrategy do
subject { described_class.new(name, resource) } subject { described_class.new(name, version, resource) }
let(:name) { "foo" } let(:name) { "foo" }
let(:url) { "http://bucket.s3.amazonaws.com/foo.tar.gz" } let(:url) { "http://bucket.s3.amazonaws.com/foo.tar.gz" }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}, version: nil) } let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: {}) }
describe "#_fetch" do describe "#_fetch" do
subject { described_class.new(name, resource)._fetch } subject { described_class.new(name, version, resource)._fetch }
context "when given Bad S3 URL" do context "when given Bad S3 URL" do
let(:url) { "http://example.com/foo.tar.gz" } let(:url) { "http://example.com/foo.tar.gz" }
@ -224,18 +231,19 @@ describe S3DownloadStrategy do
end end
describe CurlDownloadStrategy do describe CurlDownloadStrategy do
subject { described_class.new(name, resource) } subject { described_class.new(name, version, resource) }
let(:name) { "foo" } let(:name) { "foo" }
let(:url) { "http://example.com/foo.tar.gz" } let(:url) { "http://example.com/foo.tar.gz" }
let(:resource) { double(Resource, url: url, mirrors: [], specs: { user: "download:123456" }, version: nil) } let(:version) { nil }
let(:resource) { double(Resource, url: url, mirrors: [], specs: { user: "download:123456" }) }
it "parses the opts and sets the corresponding args" do it "parses the opts and sets the corresponding args" do
expect(subject.send(:_curl_opts)).to eq(["--user", "download:123456"]) expect(subject.send(:_curl_opts)).to eq(["--user", "download:123456"])
end end
describe "#tarball_path" do describe "#tarball_path" do
subject { described_class.new(name, resource).tarball_path } subject { described_class.new(name, version, resource).tarball_path }
context "when URL ends with file" do context "when URL ends with file" do
it { is_expected.to eq(HOMEBREW_CACHE/"foo-.tar.gz") } it { is_expected.to eq(HOMEBREW_CACHE/"foo-.tar.gz") }
@ -251,12 +259,13 @@ end
describe ScpDownloadStrategy do describe ScpDownloadStrategy do
def resource_for(url) def resource_for(url)
double(Resource, url: url, mirrors: [], specs: {}, version: nil) double(Resource, url: url, mirrors: [], specs: {})
end end
subject { described_class.new(name, resource) } subject { described_class.new(name, version, resource) }
let(:name) { "foo" } let(:name) { "foo" }
let(:url) { "scp://example.com/foo.tar.gz" } let(:url) { "scp://example.com/foo.tar.gz" }
let(:version) { nil }
let(:resource) { resource_for(url) } let(:resource) { resource_for(url) }
describe "#initialize" do describe "#initialize" do
@ -271,7 +280,7 @@ describe ScpDownloadStrategy do
context "with invalid URL #{invalid_url}" do context "with invalid URL #{invalid_url}" do
it "raises ScpDownloadStrategyError" do it "raises ScpDownloadStrategyError" do
expect { expect {
described_class.new(name, resource_for(invalid_url)) described_class.new(name, version, resource_for(invalid_url))
}.to raise_error(ScpDownloadStrategyError) }.to raise_error(ScpDownloadStrategyError)
end end
end end