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
|
require 'open-uri'
class Downloader
class GNU < self
def self.download(name, *rest)
super("http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=#{name};hb=HEAD", name, *rest)
end
end
class RubyGems < self
def self.download(url, name, dir = nil, ims = true, options = {})
options[:ssl_ca_cert] = Dir.glob(File.expand_path("../lib/rubygems/ssl_certs/*.pem", File.dirname(__FILE__)))
super("https://rubygems.org/downloads/#{name}", name, dir, ims. options)
end
end
Gems = RubyGems
class Unicode < self
def self.download(name, *rest)
super("http://www.unicode.org/Public/#{name}", name, *rest)
end
end
def self.mode_for(data)
/\A#!/ =~ data ? 0755 : 0644
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
end
# Downloader.download(url, name, [dir, [ims]])
#
# 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.
# If +ims+ is false, always download url regardless of its last
# modified time.
#
# Example usage:
# download 'http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt',
# 'UnicodeData.txt', 'enc/unicode/data'
def self.download(url, name, dir = nil, ims = true, options = {})
file = dir ? File.join(dir, File.basename(name)) : name
if ims.nil? and File.exist?(file)
if $VERBOSE
$stdout.puts "#{name} already exists"
$stdout.flush
end
return true
end
url = URI(url)
if $VERBOSE
$stdout.print "downloading #{name} ... "
$stdout.flush
end
begin
data = url.read(options.merge(http_options(file, ims.nil? ? true : ims)))
rescue OpenURI::HTTPError => 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 e.class, "failed to download #{name}\n#{e.message}: #{url}", e.backtrace
end
end
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
|