mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

We need to limit the interface that is exposed to the downloader in order to make future changes easier. This will be important for work on new features, such as selecting a mirror from the command line. In the future, the existing Resource class will probably be split into multiple classes.
163 lines
3.5 KiB
Ruby
163 lines
3.5 KiB
Ruby
require 'download_strategy'
|
|
require 'checksum'
|
|
require 'version'
|
|
|
|
# Resource is the fundamental representation of an external resource. The
|
|
# primary formula download, along with other declared resources, are instances
|
|
# of this class.
|
|
class Resource
|
|
include FileUtils
|
|
|
|
attr_reader :checksum, :mirrors, :specs, :using
|
|
attr_writer :url, :checksum, :version
|
|
attr_accessor :download_strategy
|
|
|
|
# Formula name must be set after the DSL, as we have no access to the
|
|
# formula name before initialization of the formula
|
|
attr_accessor :name, :owner
|
|
|
|
class Download
|
|
def initialize(resource)
|
|
@resource = resource
|
|
end
|
|
|
|
def url
|
|
@resource.url
|
|
end
|
|
|
|
def specs
|
|
@resource.specs
|
|
end
|
|
|
|
def version
|
|
@resource.version
|
|
end
|
|
|
|
def mirrors
|
|
@resource.mirrors
|
|
end
|
|
end
|
|
|
|
def initialize name=nil, &block
|
|
@name = name
|
|
@url = nil
|
|
@version = nil
|
|
@mirrors = []
|
|
@specs = {}
|
|
@checksum = nil
|
|
@using = nil
|
|
instance_eval(&block) if block_given?
|
|
end
|
|
|
|
def downloader
|
|
@downloader ||= download_strategy.new(download_name, Download.new(self))
|
|
end
|
|
|
|
# Removes /s from resource names; this allows go package names
|
|
# to be used as resource names without confusing software that
|
|
# interacts with download_name, e.g. github.com/foo/bar
|
|
def escaped_name
|
|
name.gsub("/", '-')
|
|
end
|
|
|
|
def download_name
|
|
name.nil? ? owner.name : "#{owner.name}--#{escaped_name}"
|
|
end
|
|
|
|
def cached_download
|
|
downloader.cached_location
|
|
end
|
|
|
|
def clear_cache
|
|
downloader.clear_cache
|
|
end
|
|
|
|
# Fetch, verify, and unpack the resource
|
|
def stage(target=nil, &block)
|
|
verify_download_integrity(fetch)
|
|
unpack(target, &block)
|
|
end
|
|
|
|
# If a target is given, unpack there; else unpack to a temp folder
|
|
# If block is given, yield to that block
|
|
# A target or a block must be given, but not both
|
|
def unpack(target=nil)
|
|
mktemp(download_name) do
|
|
downloader.stage
|
|
if block_given?
|
|
yield self
|
|
elsif target
|
|
target = Pathname.new(target) unless target.is_a? Pathname
|
|
target.install Dir['*']
|
|
end
|
|
end
|
|
end
|
|
|
|
Partial = Struct.new(:resource, :files)
|
|
|
|
def files(*files)
|
|
Partial.new(self, files)
|
|
end
|
|
|
|
def fetch
|
|
HOMEBREW_CACHE.mkpath
|
|
|
|
begin
|
|
downloader.fetch
|
|
rescue ErrorDuringExecution, CurlDownloadStrategyError => e
|
|
raise DownloadError.new(self, e)
|
|
end
|
|
|
|
cached_download
|
|
end
|
|
|
|
def verify_download_integrity fn
|
|
if fn.file?
|
|
ohai "Verifying #{fn.basename} checksum" if ARGV.verbose?
|
|
fn.verify_checksum(checksum)
|
|
end
|
|
rescue ChecksumMissingError
|
|
opoo "Cannot verify integrity of #{fn.basename}"
|
|
puts "A checksum was not provided for this resource"
|
|
puts "For your reference the SHA1 is: #{fn.sha1}"
|
|
end
|
|
|
|
Checksum::TYPES.each do |type|
|
|
define_method(type) { |val| @checksum = Checksum.new(type, val) }
|
|
end
|
|
|
|
def url val=nil, specs={}
|
|
return @url if val.nil?
|
|
@url = val
|
|
@specs.merge!(specs)
|
|
@using = @specs.delete(:using)
|
|
@download_strategy = DownloadStrategyDetector.detect(url, using)
|
|
end
|
|
|
|
def version val=nil
|
|
@version ||= detect_version(val)
|
|
end
|
|
|
|
def mirror val
|
|
mirrors << val
|
|
end
|
|
|
|
private
|
|
|
|
def detect_version(val)
|
|
case val
|
|
when nil then Version.detect(url, specs)
|
|
when String then Version.new(val)
|
|
when Version then val
|
|
else
|
|
raise TypeError, "version '#{val.inspect}' should be a string"
|
|
end
|
|
end
|
|
|
|
class Go < Resource
|
|
def stage target
|
|
super(target/name)
|
|
end
|
|
end
|
|
end
|