| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
 | 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 :mirrors, :specs, :using
  attr_writer :version
  attr_accessor :download_strategy, :checksum
  # 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
    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
  def stage(target=nil, &block)
    unless target || block
      raise ArgumentError, "target directory or block is required"
    end
    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 SHA256 is: #{fn.sha256}"
  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)
    return if val.nil? && url.nil?
    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
 |