aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
authorMasayuki Morita2017-01-02 12:56:20 +0900
committerMasayuki Morita2017-01-02 15:56:55 +0900
commitb9cc52db455b879fa048421851d7bd43bddde817 (patch)
tree4d8433b98d9726bedd702a394f766a89c10d2299 /Library
parent3e0d54d8b9be1507c61e7a862379d7c9ad31fb8a (diff)
downloadbrew-b9cc52db455b879fa048421851d7bd43bddde817.tar.bz2
New feature: GitHubReleaseDownloadStrategy
GitHubReleaseDownloadStrategy downloads tarballs from GitHub Release assets. To use it, add ":using => GitHubReleaseDownloadStrategy" to the URL section of your formula. This download strategy uses GitHub access tokens (in the environment variables GITHUB_TOKEN) to sign the request. This strategy is suitable for corporate use just like S3DownloadStrategy, because it lets you use a private GttHub repository for internal distribution. It works with public one, but in that case simply use CurlDownloadStrategy.
Diffstat (limited to 'Library')
-rw-r--r--Library/Homebrew/download_strategy.rb76
-rw-r--r--Library/Homebrew/test/download_strategies_test.rb47
2 files changed, 122 insertions, 1 deletions
diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb
index 9f9b2abab..fa54ef716 100644
--- a/Library/Homebrew/download_strategy.rb
+++ b/Library/Homebrew/download_strategy.rb
@@ -532,6 +532,82 @@ class S3DownloadStrategy < CurlDownloadStrategy
end
end
+# GitHubReleaseDownloadStrategy downloads tarballs from GitHub Release assets.
+# To use it, add ":using => GitHubReleaseDownloadStrategy" to the URL section
+# of your formula. This download strategy uses GitHub access tokens (in the
+# environment variables GITHUB_TOKEN) to sign the request.
+# This strategy is suitable for corporate use just like S3DownloadStrategy,
+# because it lets you use a private GttHub repository for internal distribution.
+# It works with public one, but in that case simply use CurlDownloadStrategy.
+class GitHubReleaseDownloadStrategy < CurlDownloadStrategy
+ require 'open-uri'
+
+ def initialize(name, resource)
+ super
+
+ @github_token = ENV["GITHUB_TOKEN"]
+ unless @github_token
+ puts "Environmental variable GITHUB_TOKEN is required."
+ raise CurlDownloadStrategyError, @url
+ end
+
+ url_pattern = %r|https://github.com/(\S+)/(\S+)/releases/download/(\S+)/(\S+)|
+ unless @url =~ url_pattern
+ puts "Invalid url pattern for GitHub Release."
+ raise CurlDownloadStrategyError, @url
+ end
+
+ _, @owner, @repo, @tag, @filename = *(@url.match(url_pattern))
+ end
+
+ def _fetch
+ puts "Download asset_id: #{asset_id}"
+ # HTTP request header `Accept: application/octet-stream` is required.
+ # Without this, the GitHub API will respond with metadata, not binary.
+ curl asset_url, "-C", downloaded_size, "-o", temporary_path, "-H", 'Accept: application/octet-stream'
+ end
+
+ private
+
+ def asset_url
+ "https://#{@github_token}@api.github.com/repos/#{@owner}/#{@repo}/releases/assets/#{asset_id}"
+ end
+
+ def asset_id
+ @asset_id ||= resolve_asset_id
+ end
+
+ def resolve_asset_id
+ release_metadata = fetch_release_metadata
+ assets = release_metadata["assets"].select{ |a| a["name"] == @filename }
+ if assets.empty?
+ puts "Asset file not found."
+ raise CurlDownloadStrategyError, @url
+ end
+
+ return assets.first["id"]
+ end
+
+ def release_url
+ "https://api.github.com/repos/#{@owner}/#{@repo}/releases/tags/#{@tag}"
+ end
+
+ def fetch_release_metadata
+ begin
+ release_response = open(release_url, {:http_basic_authentication => [@github_token]}).read
+ rescue OpenURI::HTTPError => e
+ if e.message == '404 Not Found'
+ puts "GitHub Release not found."
+ raise CurlDownloadStrategyError, @url
+ else
+ raise e
+ end
+ end
+
+ return JSON.parse(release_response)
+ end
+end
+
class SubversionDownloadStrategy < VCSDownloadStrategy
def initialize(name, resource)
super
diff --git a/Library/Homebrew/test/download_strategies_test.rb b/Library/Homebrew/test/download_strategies_test.rb
index 87218fb12..1df0267af 100644
--- a/Library/Homebrew/test/download_strategies_test.rb
+++ b/Library/Homebrew/test/download_strategies_test.rb
@@ -2,11 +2,12 @@ require "testing_env"
require "download_strategy"
class ResourceDouble
- attr_reader :url, :specs, :version
+ attr_reader :url, :specs, :version, :mirrors
def initialize(url = "http://example.com/foo.tar.gz", specs = {})
@url = url
@specs = specs
+ @mirrors = []
end
end
@@ -60,6 +61,50 @@ class VCSDownloadStrategyTests < Homebrew::TestCase
end
end
+class GitHubReleaseDownloadStrategyTests < Homebrew::TestCase
+ def setup
+ resource = ResourceDouble.new("https://github.com/owner/repo/releases/download/tag/foo_v0.1.0_darwin_amd64.tar.gz")
+ ENV["GITHUB_TOKEN"] = "token"
+ @strategy = GitHubReleaseDownloadStrategy.new("foo", resource)
+ end
+
+ def test_initialize
+ assert_equal "token", @strategy.instance_variable_get(:@github_token)
+ assert_equal "owner", @strategy.instance_variable_get(:@owner)
+ assert_equal "repo", @strategy.instance_variable_get(:@repo)
+ assert_equal "tag", @strategy.instance_variable_get(:@tag)
+ assert_equal "foo_v0.1.0_darwin_amd64.tar.gz", @strategy.instance_variable_get(:@filename)
+ end
+
+ def test_asset_url
+ @strategy.stubs(:resolve_asset_id).returns(456)
+ expected = "https://token@api.github.com/repos/owner/repo/releases/assets/456"
+ assert_equal expected, @strategy.send(:asset_url)
+ end
+
+ def test_resolve_asset_id
+ release_metadata = {
+ "assets" => [
+ {
+ "id" => 123,
+ "name" => "foo_v0.1.0_linux_amd64.tar.gz",
+ },
+ {
+ "id" => 456,
+ "name" => "foo_v0.1.0_darwin_amd64.tar.gz",
+ },
+ ]
+ }
+ @strategy.stubs(:fetch_release_metadata).returns(release_metadata)
+ assert_equal 456, @strategy.send(:resolve_asset_id)
+ end
+
+ def test_release_url
+ expected = "https://api.github.com/repos/owner/repo/releases/tags/tag"
+ assert_equal expected, @strategy.send(:release_url)
+ end
+end
+
class GitDownloadStrategyTests < Homebrew::TestCase
include FileUtils