2013-06-14 00:01:54 -04:00
|
|
|
require 'open-uri'
|
2014-12-25 11:25:57 -05:00
|
|
|
begin
|
|
|
|
require 'net/https'
|
|
|
|
$rubygems_schema = '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 <<File
|
|
|
|
alias orig_directory? directory?
|
|
|
|
def File.directory? files
|
|
|
|
files.is_a?(Array) ? false : orig_directory?(files)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rescue LoadError
|
|
|
|
$rubygems_schema = 'http'
|
|
|
|
end
|
2013-06-14 00:01:54 -04:00
|
|
|
|
2014-06-23 21:26:21 -04:00
|
|
|
class Downloader
|
2014-09-27 22:54:59 -04:00
|
|
|
class GNU < self
|
|
|
|
def self.download(name, *rest)
|
2015-01-19 21:25:58 -05:00
|
|
|
super("http://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=#{name};hb=master", name, *rest)
|
2014-09-27 22:54:59 -04:00
|
|
|
end
|
2014-09-23 07:56:30 -04:00
|
|
|
end
|
|
|
|
|
2014-09-27 22:54:59 -04:00
|
|
|
class RubyGems < self
|
2014-12-23 22:06:59 -05:00
|
|
|
def self.download(name, dir = nil, ims = true, options = {})
|
2015-01-14 02:45:28 -05:00
|
|
|
require 'rubygems'
|
|
|
|
require 'rubygems/package'
|
2014-12-23 20:29:03 -05:00
|
|
|
options[:ssl_ca_cert] = Dir.glob(File.expand_path("../lib/rubygems/ssl_certs/*.pem", File.dirname(__FILE__)))
|
2014-12-25 11:25:57 -05:00
|
|
|
if $rubygems_schema != 'https'
|
|
|
|
warn "*** using http instead of https ***"
|
|
|
|
end
|
2015-01-14 02:45:28 -05:00
|
|
|
file = under(dir, name)
|
|
|
|
super("#{$rubygems_schema}://rubygems.org/downloads/#{name}", file, nil, ims, options) or
|
|
|
|
return false
|
2015-01-17 01:55:20 -05:00
|
|
|
policy = Gem::Security::LowSecurity
|
2015-01-31 06:40:43 -05:00
|
|
|
(policy = policy.dup).ui = Gem::SilentUI.new if policy.respond_to?(:'ui=')
|
2015-01-14 02:45:28 -05:00
|
|
|
pkg = Gem::Package.new(file)
|
2015-01-17 01:55:20 -05:00
|
|
|
pkg.security_policy = policy
|
2015-01-14 02:45:28 -05:00
|
|
|
begin
|
|
|
|
pkg.verify
|
|
|
|
rescue Gem::Security::Exception => e
|
|
|
|
$stderr.puts e.message
|
|
|
|
File.unlink(file)
|
|
|
|
false
|
|
|
|
else
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.verify(pkg)
|
2014-09-27 22:54:59 -04:00
|
|
|
end
|
2014-09-23 07:56:30 -04:00
|
|
|
end
|
|
|
|
|
2014-09-27 22:54:59 -04:00
|
|
|
Gems = RubyGems
|
2014-09-24 04:55:09 -04:00
|
|
|
|
2014-09-27 22:54:59 -04:00
|
|
|
class Unicode < self
|
|
|
|
def self.download(name, *rest)
|
2014-10-30 03:39:51 -04:00
|
|
|
super("http://www.unicode.org/Public/#{name}", name, *rest)
|
2014-09-23 07:56:30 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-09-23 07:52:23 -04:00
|
|
|
def self.mode_for(data)
|
2014-09-28 17:47:59 -04:00
|
|
|
/\A#!/ =~ data ? 0755 : 0644
|
2014-09-23 07:52:23 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.http_options(file, since)
|
|
|
|
options = {}
|
|
|
|
if since
|
|
|
|
case since
|
|
|
|
when true
|
|
|
|
since = (File.mtime(file).httpdate rescue nil)
|
|
|
|
when Time
|
|
|
|
since = since.httpdate
|
|
|
|
end
|
|
|
|
if since
|
|
|
|
options['If-Modified-Since'] = since
|
|
|
|
end
|
|
|
|
end
|
|
|
|
options
|
2014-06-23 21:26:21 -04:00
|
|
|
end
|
2014-09-23 03:08:16 -04:00
|
|
|
|
2014-09-23 07:52:23 -04:00
|
|
|
# Downloader.download(url, name, [dir, [ims]])
|
|
|
|
#
|
2014-09-23 03:08:03 -04:00
|
|
|
# Update a file from url if newer version is available.
|
|
|
|
# Creates the file if the file doesn't yet exist; however, the
|
|
|
|
# directory where the file is being created has to exist already.
|
2014-09-23 21:43:44 -04:00
|
|
|
# If +ims+ is false, always download url regardless of its last
|
2014-09-23 07:52:23 -04:00
|
|
|
# modified time.
|
|
|
|
#
|
2014-09-23 03:08:03 -04:00
|
|
|
# Example usage:
|
2014-10-05 21:15:23 -04:00
|
|
|
# download 'http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt',
|
|
|
|
# 'UnicodeData.txt', 'enc/unicode/data'
|
2014-12-23 10:06:40 -05:00
|
|
|
def self.download(url, name, dir = nil, ims = true, options = {})
|
2015-01-14 02:45:28 -05:00
|
|
|
file = under(dir, name)
|
2014-11-19 10:06:04 -05:00
|
|
|
if ims.nil? and File.exist?(file)
|
|
|
|
if $VERBOSE
|
|
|
|
$stdout.puts "#{name} already exists"
|
|
|
|
$stdout.flush
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
2014-09-27 22:54:59 -04:00
|
|
|
url = URI(url)
|
|
|
|
if $VERBOSE
|
|
|
|
$stdout.print "downloading #{name} ... "
|
|
|
|
$stdout.flush
|
|
|
|
end
|
2014-09-23 07:52:23 -04:00
|
|
|
begin
|
2014-12-23 10:06:40 -05:00
|
|
|
data = url.read(options.merge(http_options(file, ims.nil? ? true : ims)))
|
2014-09-23 07:52:23 -04:00
|
|
|
rescue OpenURI::HTTPError => http_error
|
2014-09-27 22:54:59 -04:00
|
|
|
if http_error.message =~ /^304 / # 304 Not Modified
|
|
|
|
if $VERBOSE
|
|
|
|
$stdout.puts "not modified"
|
|
|
|
$stdout.flush
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
2014-09-23 07:52:23 -04:00
|
|
|
raise
|
2014-10-20 06:48:52 -04:00
|
|
|
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
|
2014-09-23 03:08:03 -04:00
|
|
|
end
|
2014-09-23 07:52:23 -04:00
|
|
|
mtime = nil
|
|
|
|
open(file, "wb", 0600) do |f|
|
|
|
|
f.write(data)
|
|
|
|
f.chmod(mode_for(data))
|
|
|
|
mtime = data.meta["last-modified"]
|
2014-09-23 03:08:03 -04:00
|
|
|
end
|
2014-09-23 07:52:23 -04:00
|
|
|
if mtime
|
|
|
|
mtime = Time.httpdate(mtime)
|
|
|
|
File.utime(mtime, mtime, file)
|
|
|
|
end
|
2014-09-27 22:54:59 -04:00
|
|
|
if $VERBOSE
|
|
|
|
$stdout.puts "done"
|
|
|
|
$stdout.flush
|
|
|
|
end
|
2014-09-23 07:52:23 -04:00
|
|
|
true
|
|
|
|
rescue => e
|
2014-12-23 23:00:27 -05:00
|
|
|
raise "failed to download #{name}\n#{e.message}: #{url}"
|
2014-09-23 07:52:23 -04:00
|
|
|
end
|
2015-01-14 02:45:28 -05:00
|
|
|
|
|
|
|
def self.under(dir, name)
|
|
|
|
dir ? File.join(dir, File.basename(name)) : name
|
|
|
|
end
|
2013-06-14 00:01:54 -04:00
|
|
|
end
|
2014-09-28 07:27:22 -04:00
|
|
|
|
|
|
|
if $0 == __FILE__
|
|
|
|
ims = true
|
|
|
|
until ARGV.empty?
|
|
|
|
case ARGV[0]
|
|
|
|
when '-d'
|
|
|
|
destdir = ARGV[1]
|
2014-09-28 17:47:59 -04:00
|
|
|
ARGV.shift
|
2014-09-28 07:27:22 -04:00
|
|
|
when '-e'
|
|
|
|
ims = nil
|
2014-10-20 10:58:06 -04:00
|
|
|
when '-a'
|
|
|
|
ims = true
|
2014-09-28 07:27:22 -04:00
|
|
|
when /\A-/
|
|
|
|
abort "#{$0}: unknown option #{ARGV[0]}"
|
|
|
|
else
|
|
|
|
break
|
|
|
|
end
|
2014-09-28 17:47:59 -04:00
|
|
|
ARGV.shift
|
2014-09-28 07:27:22 -04:00
|
|
|
end
|
|
|
|
dl = Downloader.constants.find do |name|
|
|
|
|
ARGV[0].casecmp(name.to_s) == 0
|
2014-10-30 03:39:51 -04:00
|
|
|
end unless ARGV.empty?
|
2014-09-28 07:27:22 -04:00
|
|
|
$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
|
2014-09-28 11:26:21 -04:00
|
|
|
Downloader.download(ARGV[0], ARGV[1], destdir, ims)
|
2014-09-28 07:27:22 -04:00
|
|
|
end
|
|
|
|
end
|