require 'open-uri' begin require 'net/https' rescue LoadError https = 'http' else https = 'https' # open-uri of ruby 2.2.0 accept an array of PEMs as ssl_ca_cert, but old # versions are not. so, patching OpenSSL::X509::Store#add_file instead. class OpenSSL::X509::Store alias orig_add_file add_file def add_file(pems) Array(pems).each do |pem| if File.directory?(pem) add_path pem else orig_add_file pem end end end end # since open-uri internally checks ssl_ca_cert by File.directory?, to allow # accept an array. class < http_error if http_error.message =~ /^304 / # 304 Not Modified if $VERBOSE $stdout.puts "not modified" $stdout.flush end return true end raise rescue Timeout::Error if ims.nil? and File.exist?(file) puts "Request for #{url} timed out, using old version." return true end raise rescue SocketError if ims.nil? and File.exist?(file) puts "No network connection, unable to download #{url}, using old version." return true end raise end mtime = nil open(file, "wb", 0600) do |f| f.write(data) f.chmod(mode_for(data)) mtime = data.meta["last-modified"] end if mtime mtime = Time.httpdate(mtime) File.utime(mtime, mtime, file) end if $VERBOSE $stdout.puts "done" $stdout.flush end true rescue => e raise "failed to download #{name}\n#{e.message}: #{url}" end def self.under(dir, name) dir ? File.join(dir, File.basename(name)) : name end end Downloader.class_variable_set(:@@https, https.freeze) if $0 == __FILE__ ims = true until ARGV.empty? case ARGV[0] when '-d' destdir = ARGV[1] ARGV.shift when '-e' ims = nil when '-a' ims = true when /\A-/ abort "#{$0}: unknown option #{ARGV[0]}" else break end ARGV.shift end dl = Downloader.constants.find do |name| ARGV[0].casecmp(name.to_s) == 0 end unless ARGV.empty? $VERBOSE = true if dl dl = Downloader.const_get(dl) ARGV.shift ARGV.each do |name| dl.download(name, destdir, ims) end else abort "usage: #{$0} url name" unless ARGV.size == 2 Downloader.download(ARGV[0], ARGV[1], destdir, ims) end end