brew: Add ScpDownloadStrategy
This commit is contained in:
parent
94c0d833c3
commit
fe8939ddd0
@ -594,6 +594,70 @@ class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDo
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# ScpDownloadStrategy downloads files using ssh via scp. To use it, add
|
||||||
|
# ":using => ScpDownloadStrategy" to the URL section of your formula or
|
||||||
|
# provide a URL starting with scp://. This strategy uses ssh credentials for
|
||||||
|
# authentication. If a public/private keypair is configured, it will not
|
||||||
|
# prompt for a password.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# class Abc < Formula
|
||||||
|
# url "scp://example.com/src/abc.1.0.tar.gz"
|
||||||
|
# ...
|
||||||
|
class ScpDownloadStrategy < AbstractFileDownloadStrategy
|
||||||
|
attr_reader :tarball_path, :temporary_path
|
||||||
|
|
||||||
|
def initialize(name, resource)
|
||||||
|
super
|
||||||
|
@tarball_path = HOMEBREW_CACHE/"#{name}-#{version}#{ext}"
|
||||||
|
@temporary_path = Pathname.new("#{cached_location}.incomplete")
|
||||||
|
parse_url_pattern
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_url_pattern
|
||||||
|
url_pattern = %r{scp://([^@]+@)?([^@:/]+)(:\d+)?/(\S+)}
|
||||||
|
if @url !~ url_pattern
|
||||||
|
raise ScpDownloadStrategyError, "Invalid URL for scp: #{@url}"
|
||||||
|
end
|
||||||
|
|
||||||
|
_, @user, @host, @port, @path = *@url.match(url_pattern)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch
|
||||||
|
ohai "Downloading #{@url}"
|
||||||
|
|
||||||
|
if cached_location.exist?
|
||||||
|
puts "Already downloaded: #{cached_location}"
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
safe_system "scp", scp_source, temporary_path.to_s
|
||||||
|
rescue ErrorDuringExecution
|
||||||
|
raise ScpDownloadStrategyError, "Failed to run scp #{scp_source}"
|
||||||
|
end
|
||||||
|
|
||||||
|
ignore_interrupts { temporary_path.rename(cached_location) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cached_location
|
||||||
|
tarball_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_cache
|
||||||
|
super
|
||||||
|
rm_rf(temporary_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def scp_source
|
||||||
|
path_prefix = "/" unless @path.start_with?("~")
|
||||||
|
port_arg = "-P #{@port[1..-1]} " if @port
|
||||||
|
"#{port_arg}#{@user}#{@host}:#{path_prefix}#{@path}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class SubversionDownloadStrategy < VCSDownloadStrategy
|
class SubversionDownloadStrategy < VCSDownloadStrategy
|
||||||
def initialize(name, resource)
|
def initialize(name, resource)
|
||||||
super
|
super
|
||||||
@ -1140,6 +1204,8 @@ class DownloadStrategyDetector
|
|||||||
when %r{^s3://}
|
when %r{^s3://}
|
||||||
require_aws_sdk
|
require_aws_sdk
|
||||||
S3DownloadStrategy
|
S3DownloadStrategy
|
||||||
|
when %r{^scp://}
|
||||||
|
ScpDownloadStrategy
|
||||||
else
|
else
|
||||||
CurlDownloadStrategy
|
CurlDownloadStrategy
|
||||||
end
|
end
|
||||||
|
|||||||
@ -515,6 +515,13 @@ class CurlDownloadStrategyError < RuntimeError
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# raised in ScpDownloadStrategy.fetch
|
||||||
|
class ScpDownloadStrategyError < RuntimeError
|
||||||
|
def initialize(cause)
|
||||||
|
super "Download failed: #{cause}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# raised by safe_system in utils.rb
|
# raised by safe_system in utils.rb
|
||||||
class ErrorDuringExecution < RuntimeError
|
class ErrorDuringExecution < RuntimeError
|
||||||
def initialize(cmd, args = [])
|
def initialize(cmd, args = [])
|
||||||
|
|||||||
@ -268,6 +268,90 @@ describe CurlDownloadStrategy do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ScpDownloadStrategy do
|
||||||
|
def resource_for(url)
|
||||||
|
double(Resource, url: url, mirrors: [], specs: {}, version: nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(name, resource) }
|
||||||
|
let(:name) { "foo" }
|
||||||
|
let(:url) { "scp://example.com/foo.tar.gz" }
|
||||||
|
let(:resource) { resource_for(url) }
|
||||||
|
|
||||||
|
describe "#initialize" do
|
||||||
|
invalid_urls = %w[
|
||||||
|
http://example.com/foo.tar.gz
|
||||||
|
scp://@example.com/foo.tar.gz
|
||||||
|
scp://example.com:/foo.tar.gz
|
||||||
|
scp://example.com
|
||||||
|
]
|
||||||
|
|
||||||
|
invalid_urls.each do |invalid_url|
|
||||||
|
context "with invalid URL #{invalid_url}" do
|
||||||
|
it "raises ScpDownloadStrategyError" do
|
||||||
|
expect {
|
||||||
|
described_class.new(name, resource_for(invalid_url))
|
||||||
|
}.to raise_error(ScpDownloadStrategyError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#fetch" do
|
||||||
|
before do
|
||||||
|
expect(subject.temporary_path).to receive(:rename).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when given a valid URL" do
|
||||||
|
let(:url) { "scp://example.com/foo.tar.gz" }
|
||||||
|
it "copies the file via scp" do
|
||||||
|
expect(subject)
|
||||||
|
.to receive(:safe_system)
|
||||||
|
.with("scp", "example.com:/foo.tar.gz", anything)
|
||||||
|
.and_return(true)
|
||||||
|
|
||||||
|
subject.fetch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when given a URL with a username" do
|
||||||
|
let(:url) { "scp://user@example.com/foo.tar.gz" }
|
||||||
|
it "copies the file via scp" do
|
||||||
|
expect(subject)
|
||||||
|
.to receive(:safe_system)
|
||||||
|
.with("scp", "user@example.com:/foo.tar.gz", anything)
|
||||||
|
.and_return(true)
|
||||||
|
|
||||||
|
subject.fetch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when given a URL with a port" do
|
||||||
|
let(:url) { "scp://example.com:1234/foo.tar.gz" }
|
||||||
|
it "copies the file via scp" do
|
||||||
|
expect(subject)
|
||||||
|
.to receive(:safe_system)
|
||||||
|
.with("scp", "-P 1234 example.com:/foo.tar.gz", anything)
|
||||||
|
.and_return(true)
|
||||||
|
|
||||||
|
subject.fetch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when given a URL with /~/" do
|
||||||
|
let(:url) { "scp://example.com/~/foo.tar.gz" }
|
||||||
|
it "treats the path as relative to the home directory" do
|
||||||
|
expect(subject)
|
||||||
|
.to receive(:safe_system)
|
||||||
|
.with("scp", "example.com:~/foo.tar.gz", anything)
|
||||||
|
.and_return(true)
|
||||||
|
|
||||||
|
subject.fetch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe DownloadStrategyDetector do
|
describe DownloadStrategyDetector do
|
||||||
describe "::detect" do
|
describe "::detect" do
|
||||||
subject { described_class.detect(url, strategy) }
|
subject { described_class.detect(url, strategy) }
|
||||||
@ -306,6 +390,11 @@ describe DownloadStrategyDetector do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when given an scp URL" do
|
||||||
|
let(:url) { "scp://example.com/brew.tar.gz" }
|
||||||
|
it { is_expected.to eq(ScpDownloadStrategy) }
|
||||||
|
end
|
||||||
|
|
||||||
it "defaults to cURL" do
|
it "defaults to cURL" do
|
||||||
expect(subject).to eq(CurlDownloadStrategy)
|
expect(subject).to eq(CurlDownloadStrategy)
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user