net_fetcher.rb 3.65 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#
# Copyright:: Copyright (c) 2012 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

18
19
module Omnibus

20
21
22
23
24
25
  class UnsupportedURIScheme < ArgumentError
  end

  class InvalidSourceFile < RuntimeError
  end

26
27
28
  # Fetcher Implementation for HTTP and FTP hosted tarballs
  class NetFetcher < Fetcher

Daniel DeLeo's avatar
Daniel DeLeo committed
29
30
    name :net

31
    attr_reader :name
32
33
34
35
    attr_reader :project_file
    attr_reader :source
    attr_reader :source_uri
    attr_reader :source_dir
Marc Paradise's avatar
Marc Paradise committed
36
    attr_reader :project_dir
37
38

    def initialize(software)
39
40
      @name         = software.name
      @checksum     = software.checksum
41
42
43
44
      @source       = software.source
      @project_file = software.project_file
      @source_uri   = software.source_uri
      @source_dir   = software.source_dir
Marc Paradise's avatar
Marc Paradise committed
45
      @project_dir  = software.project_dir
46
47
48
49
    end

    def description
      s=<<-E
Daniel DeLeo's avatar
Daniel DeLeo committed
50
source URI:     #{source_uri}
51
checksum:       #{@checksum}
52
53
54
55
local location: #@project_file
E
    end

Marc Paradise's avatar
Marc Paradise committed
56
    def fetch_required?
57
58
59
      !File.exists?(project_file) || Digest::MD5.file(project_file) != @checksum
    end

Marc Paradise's avatar
Marc Paradise committed
60

Marc Paradise's avatar
Marc Paradise committed
61
62
63
64
    def clean
      if File.exists?(project_dir) 
        log "cleaning existing build from #{project_dir}" 
        shell = Mixlib::ShellOut.new("rm -rf #{project_dir}", :live_stream => STDOUT)
65
66
        shell.run_command
        shell.error!
Marc Paradise's avatar
Marc Paradise committed
67
      end
68
      extract
Marc Paradise's avatar
Marc Paradise committed
69
70
    end

71
    def fetch
Marc Paradise's avatar
Marc Paradise committed
72
      if fetch_required?
73
74
        download
        verify_checksum!
75
      else
Marc Paradise's avatar
Marc Paradise committed
76
        log "Cached copy of source tarball up to date"
77
78
79
80
      end
    end

    def download
81
      log "fetching #{project_file} from #{source_uri}"
82

Daniel DeLeo's avatar
Daniel DeLeo committed
83
      case source_uri.scheme
84
      when /https?/
Daniel DeLeo's avatar
Daniel DeLeo committed
85
86
        http_client = Net::HTTP.new(source_uri.host, source_uri.port)
        http_client.use_ssl = (source_uri.scheme == "https")
87
        http_client.start do |http|
Daniel DeLeo's avatar
Daniel DeLeo committed
88
          resp = http.get(source_uri.path, 'accept-encoding' => '')
89
90
          open(project_file, "wb") do |f|
            f.write(resp.body)
91
92
          end
        end
93
      when "ftp"
Daniel DeLeo's avatar
Daniel DeLeo committed
94
        Net::FTP.open(source_uri.host) do |ftp|
95
96
          ftp.passive = true
          ftp.login
Daniel DeLeo's avatar
Daniel DeLeo committed
97
          ftp.getbinaryfile(source_uri.path, project_file)
98
99
100
          ftp.close
        end
      else
Daniel DeLeo's avatar
Daniel DeLeo committed
101
        raise UnsupportedURIScheme, "Don't know how to download from #{source_uri}"
102
103
      end
    rescue Exception => e
Daniel DeLeo's avatar
Daniel DeLeo committed
104
      ErrorReporter.new(e, self).explain("Failed to fetch source from #source_uri (#{e.class}: #{e.message.strip})")
105
106
107
      raise
    end

108
109
110
111
112
113
114
115
116
117
118
    def verify_checksum!
      actual_md5 = Digest::MD5.file(project_file)
      unless actual_md5 == @checksum
        log "Invalid MD5 for #@name"
        log "Expected: #{@checksum}"
        log "Actual:   #{actual_md5}"
        raise InvalidSourceFile, "Checksum of downloaded file #{project_file} doesn't match expected"
      end
    end

    def extract
119
      log "extracting the source in #{project_file} to #{source_dir}"
120
      shell = Mixlib::ShellOut.new("gzip -dc #{project_file} | tar -xf - -C #{source_dir}", :live_stream => STDOUT)
121
122
123
124
125
126
127
      shell.run_command
      shell.error!
    rescue Exception => e
      ErrorReporter.new(e, self).explain("Failed to unpack tarball at #{project_file} (#{e.class}: #{e.message.strip})")
      raise
    end

128
129
  end
end