mini_portile2 2.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +4 -0
- data.tar.gz.sig +2 -0
- data/.gitignore +3 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +169 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +20 -0
- data/README.md +188 -0
- data/Rakefile +25 -0
- data/appveyor.yml +24 -0
- data/examples/.gitignore +2 -0
- data/examples/Rakefile +127 -0
- data/examples/libiconv-patches/1-avoid-gets-error.patch +16 -0
- data/lib/mini_portile2.rb +2 -0
- data/lib/mini_portile2/mini_portile.rb +495 -0
- data/lib/mini_portile2/version.rb +3 -0
- data/mini_portile2.gemspec +30 -0
- data/test/assets/patch 1.diff +7 -0
- data/test/assets/test mini portile-1.0.0/configure +11 -0
- data/test/helper.rb +49 -0
- data/test/test_cook.rb +68 -0
- data/test/test_digest.rb +72 -0
- data/test/test_proxy.rb +121 -0
- metadata +154 -0
- metadata.gz.sig +0 -0
data/appveyor.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
install:
|
3
|
+
- ps: ((New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt', "$env:TMP\ca-bundle.crt"))
|
4
|
+
- SET SSL_CERT_FILE=%TMP%\ca-bundle.crt
|
5
|
+
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
6
|
+
- SET RAKEOPT=-rdevkit
|
7
|
+
- ruby --version
|
8
|
+
- gem --version
|
9
|
+
- bundle install
|
10
|
+
|
11
|
+
build: off
|
12
|
+
|
13
|
+
test_script:
|
14
|
+
- bundle exec rake
|
15
|
+
|
16
|
+
environment:
|
17
|
+
matrix:
|
18
|
+
- ruby_version: "22-x64"
|
19
|
+
- ruby_version: "22"
|
20
|
+
- ruby_version: "21-x64"
|
21
|
+
- ruby_version: "21"
|
22
|
+
- ruby_version: "200-x64"
|
23
|
+
- ruby_version: "200"
|
24
|
+
- ruby_version: "193"
|
data/examples/.gitignore
ADDED
data/examples/Rakefile
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), "../lib"))
|
4
|
+
require "mini_portile2"
|
5
|
+
|
6
|
+
recipes = []
|
7
|
+
|
8
|
+
def windows?
|
9
|
+
RbConfig::CONFIG['target_os'] =~ /mswin|mingw32/
|
10
|
+
end
|
11
|
+
|
12
|
+
# libiconv
|
13
|
+
libiconv = MiniPortile.new "libiconv", "1.14"
|
14
|
+
libiconv.files << "ftp://ftp.gnu.org/pub/gnu/#{libiconv.name}/#{libiconv.name}-#{libiconv.version}.tar.gz"
|
15
|
+
unless windows?
|
16
|
+
libiconv.patch_files = Dir["libiconv-patches/*.patch"].map { |dir| File.expand_path dir }
|
17
|
+
end
|
18
|
+
|
19
|
+
recipes.push libiconv
|
20
|
+
|
21
|
+
# sqlite3
|
22
|
+
sqlite3 = MiniPortile.new "sqlite3", "3.8.4.1"
|
23
|
+
sqlite3.files << "http://sqlite.org/2014/sqlite-autoconf-3080401.tar.gz"
|
24
|
+
|
25
|
+
recipes.push sqlite3
|
26
|
+
|
27
|
+
# c-ares
|
28
|
+
c_ares = MiniPortile.new "c-ares", "1.7.5"
|
29
|
+
c_ares.files << "http://distfiles.openknapsack.org/#{c_ares.name}/#{c_ares.name}-#{c_ares.version}.tar.gz"
|
30
|
+
|
31
|
+
recipes.push c_ares
|
32
|
+
|
33
|
+
# zlib
|
34
|
+
class ZlibRecipe < MiniPortile
|
35
|
+
def windows?
|
36
|
+
!(host =~ /mswin|mingw/).nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def configure
|
40
|
+
return super unless windows?
|
41
|
+
|
42
|
+
Dir.chdir work_path do
|
43
|
+
mk = File.read 'win32/Makefile.gcc'
|
44
|
+
File.open 'win32/Makefile.gcc', 'wb' do |f|
|
45
|
+
f.puts "BINARY_PATH = #{path}/bin"
|
46
|
+
f.puts "LIBRARY_PATH = #{path}/lib"
|
47
|
+
f.puts "INCLUDE_PATH = #{path}/include"
|
48
|
+
|
49
|
+
cross_build? and
|
50
|
+
mk.sub!(/^PREFIX\s*=\s*$/, "PREFIX = #{host}-")
|
51
|
+
|
52
|
+
f.puts mk
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def configure_defaults
|
58
|
+
["--static"]
|
59
|
+
end
|
60
|
+
|
61
|
+
def configured?
|
62
|
+
return super unless windows?
|
63
|
+
|
64
|
+
!!(File.read(File.join(work_path, 'win32/Makefile.gcc')) =~ /^BINARY_PATH/)
|
65
|
+
end
|
66
|
+
|
67
|
+
def compile
|
68
|
+
return super unless windows?
|
69
|
+
|
70
|
+
execute "compile", "make -f win32/Makefile.gcc"
|
71
|
+
end
|
72
|
+
|
73
|
+
def install
|
74
|
+
return if installed?
|
75
|
+
return super unless windows?
|
76
|
+
|
77
|
+
execute "install", %Q(#{make_cmd} -f win32/Makefile.gcc install)
|
78
|
+
end
|
79
|
+
|
80
|
+
def cross_build?
|
81
|
+
host != original_host
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
zlib = ZlibRecipe.new "zlib", "1.2.8"
|
86
|
+
zlib.files << {
|
87
|
+
url: "http://zlib.net/#{zlib.name}-#{zlib.version}.tar.gz",
|
88
|
+
md5: "44d667c142d7cda120332623eab69f40",
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
recipes.push zlib
|
93
|
+
|
94
|
+
namespace :ports do
|
95
|
+
directory "ports"
|
96
|
+
|
97
|
+
recipes.each do |recipe|
|
98
|
+
desc "Install port #{recipe.name} #{recipe.version}"
|
99
|
+
task recipe.name => ["ports"] do |t|
|
100
|
+
checkpoint = "ports/.#{recipe.name}-#{recipe.version}-#{recipe.host}.installed"
|
101
|
+
|
102
|
+
unless File.exist?(checkpoint)
|
103
|
+
recipe.cook
|
104
|
+
touch checkpoint
|
105
|
+
end
|
106
|
+
|
107
|
+
recipe.activate
|
108
|
+
end
|
109
|
+
|
110
|
+
task :all => recipe.name
|
111
|
+
end
|
112
|
+
|
113
|
+
desc "Install all ports and display installation location"
|
114
|
+
task :all do
|
115
|
+
recipes.each do |recipe|
|
116
|
+
puts "Artifacts of '#{recipe.name}' in '#{recipe.path}'"
|
117
|
+
end
|
118
|
+
puts "LDFLAGS: " << ENV['LDFLAGS'].inspect
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
desc "Adjust all recipes host for cross-compilation"
|
123
|
+
task :cross do
|
124
|
+
recipes.each do |recipe|
|
125
|
+
recipe.host = "i686-w64-mingw32"
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
This file tests the 'patch' functionality, as well as working around a
|
2
|
+
libiconv compilation issue with glibc >= 2.16.
|
3
|
+
|
4
|
+
--- a/srclib/stdio.in.h 2015-08-23 13:59:57.395880263 -0400
|
5
|
+
+++ b/srclib/stdio.in.h 2015-08-23 14:00:00.047880153 -0400
|
6
|
+
@@ -695,8 +695,10 @@
|
7
|
+
/* It is very rare that the developer ever has full control of stdin,
|
8
|
+
so any use of gets warrants an unconditional warning. Assume it is
|
9
|
+
always declared, since it is required by C89. */
|
10
|
+
+#if defined(__GLIBC__) && !defined(__UCLIBC__) && !__GLIBC_PREREQ(2, 16)
|
11
|
+
_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
|
12
|
+
#endif
|
13
|
+
+#endif
|
14
|
+
|
15
|
+
|
16
|
+
#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
|
@@ -0,0 +1,495 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
require 'net/ftp'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'digest/md5'
|
8
|
+
require 'open-uri'
|
9
|
+
require 'cgi'
|
10
|
+
require 'rbconfig'
|
11
|
+
require 'shellwords'
|
12
|
+
|
13
|
+
# Monkey patch for Net::HTTP by ruby open-uri fix:
|
14
|
+
# https://github.com/ruby/ruby/commit/58835a9
|
15
|
+
class Net::HTTP
|
16
|
+
private
|
17
|
+
remove_method(:edit_path)
|
18
|
+
def edit_path(path)
|
19
|
+
if proxy?
|
20
|
+
if path.start_with?("ftp://") || use_ssl?
|
21
|
+
path
|
22
|
+
else
|
23
|
+
"http://#{addr_port}#{path}"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class MiniPortile
|
32
|
+
attr_reader :name, :version, :original_host
|
33
|
+
attr_writer :configure_options
|
34
|
+
attr_accessor :host, :files, :patch_files, :target, :logger
|
35
|
+
|
36
|
+
def initialize(name, version)
|
37
|
+
@name = name
|
38
|
+
@version = version
|
39
|
+
@target = 'ports'
|
40
|
+
@files = []
|
41
|
+
@patch_files = []
|
42
|
+
@log_files = {}
|
43
|
+
@logger = STDOUT
|
44
|
+
|
45
|
+
@original_host = @host = detect_host
|
46
|
+
end
|
47
|
+
|
48
|
+
def download
|
49
|
+
files_hashs.each do |file|
|
50
|
+
download_file(file[:url], file[:local_path])
|
51
|
+
verify_file(file)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def extract
|
56
|
+
files_hashs.each do |file|
|
57
|
+
extract_file(file[:local_path], tmp_path)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def apply_patch(patch_file)
|
62
|
+
(
|
63
|
+
# Not a class variable because closures will capture self.
|
64
|
+
@apply_patch ||=
|
65
|
+
case
|
66
|
+
when which('git')
|
67
|
+
lambda { |file|
|
68
|
+
message "Running git apply with #{file}... "
|
69
|
+
# By --work-tree=. git-apply uses the current directory as
|
70
|
+
# the project root and will not search upwards for .git.
|
71
|
+
execute('patch', ["git", "--work-tree=.", "apply", file], :initial_message => false)
|
72
|
+
}
|
73
|
+
when which('patch')
|
74
|
+
lambda { |file|
|
75
|
+
message "Running patch with #{file}... "
|
76
|
+
execute('patch', ["patch", "-p1", "-i", file], :initial_message => false)
|
77
|
+
}
|
78
|
+
else
|
79
|
+
raise "Failed to complete patch task; patch(1) or git(1) is required."
|
80
|
+
end
|
81
|
+
).call(patch_file)
|
82
|
+
end
|
83
|
+
|
84
|
+
def patch
|
85
|
+
@patch_files.each do |full_path|
|
86
|
+
next unless File.exist?(full_path)
|
87
|
+
apply_patch(full_path)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def configure_options
|
92
|
+
@configure_options ||= configure_defaults
|
93
|
+
end
|
94
|
+
|
95
|
+
def configure
|
96
|
+
return if configured?
|
97
|
+
|
98
|
+
md5_file = File.join(tmp_path, 'configure.md5')
|
99
|
+
digest = Digest::MD5.hexdigest(computed_options.to_s)
|
100
|
+
File.open(md5_file, "w") { |f| f.write digest }
|
101
|
+
|
102
|
+
execute('configure', %w(sh configure) + computed_options)
|
103
|
+
end
|
104
|
+
|
105
|
+
def compile
|
106
|
+
execute('compile', make_cmd)
|
107
|
+
end
|
108
|
+
|
109
|
+
def install
|
110
|
+
return if installed?
|
111
|
+
execute('install', %Q(#{make_cmd} install))
|
112
|
+
end
|
113
|
+
|
114
|
+
def downloaded?
|
115
|
+
missing = files_hashs.detect do |file|
|
116
|
+
!File.exist?(file[:local_path])
|
117
|
+
end
|
118
|
+
|
119
|
+
missing ? false : true
|
120
|
+
end
|
121
|
+
|
122
|
+
def configured?
|
123
|
+
configure = File.join(work_path, 'configure')
|
124
|
+
makefile = File.join(work_path, 'Makefile')
|
125
|
+
md5_file = File.join(tmp_path, 'configure.md5')
|
126
|
+
|
127
|
+
stored_md5 = File.exist?(md5_file) ? File.read(md5_file) : ""
|
128
|
+
current_md5 = Digest::MD5.hexdigest(computed_options.to_s)
|
129
|
+
|
130
|
+
(current_md5 == stored_md5) && newer?(makefile, configure)
|
131
|
+
end
|
132
|
+
|
133
|
+
def installed?
|
134
|
+
makefile = File.join(work_path, 'Makefile')
|
135
|
+
target_dir = Dir.glob("#{port_path}/*").find { |d| File.directory?(d) }
|
136
|
+
|
137
|
+
newer?(target_dir, makefile)
|
138
|
+
end
|
139
|
+
|
140
|
+
def cook
|
141
|
+
download unless downloaded?
|
142
|
+
extract
|
143
|
+
patch
|
144
|
+
configure unless configured?
|
145
|
+
compile
|
146
|
+
install unless installed?
|
147
|
+
|
148
|
+
return true
|
149
|
+
end
|
150
|
+
|
151
|
+
def activate
|
152
|
+
lib_path = File.join(port_path, "lib")
|
153
|
+
vars = {
|
154
|
+
'PATH' => File.join(port_path, 'bin'),
|
155
|
+
'CPATH' => File.join(port_path, 'include'),
|
156
|
+
'LIBRARY_PATH' => lib_path
|
157
|
+
}.reject { |env, path| !File.directory?(path) }
|
158
|
+
|
159
|
+
output "Activating #{@name} #{@version} (from #{port_path})..."
|
160
|
+
vars.each do |var, path|
|
161
|
+
full_path = File.expand_path(path)
|
162
|
+
|
163
|
+
# turn into a valid Windows path (if required)
|
164
|
+
full_path.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
|
165
|
+
|
166
|
+
# save current variable value
|
167
|
+
old_value = ENV[var] || ''
|
168
|
+
|
169
|
+
unless old_value.include?(full_path)
|
170
|
+
ENV[var] = "#{full_path}#{File::PATH_SEPARATOR}#{old_value}"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# rely on LDFLAGS when cross-compiling
|
175
|
+
if File.exist?(lib_path) && (@host != @original_host)
|
176
|
+
full_path = File.expand_path(lib_path)
|
177
|
+
|
178
|
+
old_value = ENV.fetch("LDFLAGS", "")
|
179
|
+
|
180
|
+
unless old_value.include?(full_path)
|
181
|
+
ENV["LDFLAGS"] = "-L#{full_path} #{old_value}".strip
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def path
|
187
|
+
File.expand_path(port_path)
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def tmp_path
|
193
|
+
"tmp/#{@host}/ports/#{@name}/#{@version}"
|
194
|
+
end
|
195
|
+
|
196
|
+
def port_path
|
197
|
+
"#{@target}/#{@host}/#{@name}/#{@version}"
|
198
|
+
end
|
199
|
+
|
200
|
+
def archives_path
|
201
|
+
"#{@target}/archives"
|
202
|
+
end
|
203
|
+
|
204
|
+
def work_path
|
205
|
+
Dir.glob("#{tmp_path}/*").find { |d| File.directory?(d) }
|
206
|
+
end
|
207
|
+
|
208
|
+
def configure_defaults
|
209
|
+
[
|
210
|
+
"--host=#{@host}", # build for specific target (host)
|
211
|
+
"--enable-static", # build static library
|
212
|
+
"--disable-shared" # disable generation of shared object
|
213
|
+
]
|
214
|
+
end
|
215
|
+
|
216
|
+
def configure_prefix
|
217
|
+
"--prefix=#{File.expand_path(port_path)}"
|
218
|
+
end
|
219
|
+
|
220
|
+
def computed_options
|
221
|
+
[
|
222
|
+
configure_options, # customized or default options
|
223
|
+
configure_prefix, # installation target
|
224
|
+
].flatten
|
225
|
+
end
|
226
|
+
|
227
|
+
def files_hashs
|
228
|
+
@files.map do |file|
|
229
|
+
hash = case file
|
230
|
+
when String
|
231
|
+
{ :url => file }
|
232
|
+
when Hash
|
233
|
+
file.dup
|
234
|
+
else
|
235
|
+
raise ArgumentError, "files must be an Array of Stings or Hashs"
|
236
|
+
end
|
237
|
+
|
238
|
+
url = hash.fetch(:url){ raise ArgumentError, "no url given" }
|
239
|
+
filename = File.basename(url)
|
240
|
+
hash[:local_path] = File.join(archives_path, filename)
|
241
|
+
hash
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def verify_file(file)
|
246
|
+
digest = case
|
247
|
+
when exp=file[:sha256] then Digest::SHA256
|
248
|
+
when exp=file[:sha1] then Digest::SHA1
|
249
|
+
when exp=file[:md5] then Digest::MD5
|
250
|
+
end
|
251
|
+
if digest
|
252
|
+
is = digest.file(file[:local_path]).hexdigest
|
253
|
+
unless is == exp.downcase
|
254
|
+
raise "Downloaded file '#{file[:local_path]}' has wrong hash: expected: #{exp} is: #{is}"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def log_file(action)
|
260
|
+
@log_files[action] ||=
|
261
|
+
File.expand_path("#{action}.log", tmp_path).tap { |file|
|
262
|
+
File.unlink(file) if File.exist?(file)
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
def tar_exe
|
267
|
+
@@tar_exe ||= begin
|
268
|
+
%w[gtar bsdtar tar basic-bsdtar].find { |c|
|
269
|
+
which(c)
|
270
|
+
}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def tar_compression_switch(filename)
|
275
|
+
case File.extname(filename)
|
276
|
+
when '.gz', '.tgz'
|
277
|
+
'z'
|
278
|
+
when '.bz2', '.tbz2'
|
279
|
+
'j'
|
280
|
+
when '.Z'
|
281
|
+
'Z'
|
282
|
+
else
|
283
|
+
''
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# From: http://stackoverflow.com/a/5471032/7672
|
288
|
+
# Thanks, Mislav!
|
289
|
+
#
|
290
|
+
# Cross-platform way of finding an executable in the $PATH.
|
291
|
+
#
|
292
|
+
# which('ruby') #=> /usr/bin/ruby
|
293
|
+
def which(cmd)
|
294
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
295
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
296
|
+
exts.each { |ext|
|
297
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
298
|
+
return exe if File.executable? exe
|
299
|
+
}
|
300
|
+
end
|
301
|
+
return nil
|
302
|
+
end
|
303
|
+
|
304
|
+
def detect_host
|
305
|
+
return @detect_host if defined?(@detect_host)
|
306
|
+
|
307
|
+
begin
|
308
|
+
ENV["LC_ALL"], old_lc_all = "C", ENV["LC_ALL"]
|
309
|
+
|
310
|
+
output = `#{gcc_cmd} -v 2>&1`
|
311
|
+
if m = output.match(/^Target\: (.*)$/)
|
312
|
+
@detect_host = m[1]
|
313
|
+
end
|
314
|
+
|
315
|
+
@detect_host
|
316
|
+
ensure
|
317
|
+
ENV["LC_ALL"] = old_lc_all
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def extract_file(file, target)
|
322
|
+
filename = File.basename(file)
|
323
|
+
FileUtils.mkdir_p target
|
324
|
+
|
325
|
+
message "Extracting #{filename} into #{target}... "
|
326
|
+
execute('extract', [tar_exe, "#{tar_compression_switch(filename)}xf", file, "-C", target], {:cd => Dir.pwd, :initial_message => false})
|
327
|
+
end
|
328
|
+
|
329
|
+
def execute(action, command, options={})
|
330
|
+
log_out = log_file(action)
|
331
|
+
|
332
|
+
Dir.chdir (options.fetch(:cd){ work_path }) do
|
333
|
+
if options.fetch(:initial_message){ true }
|
334
|
+
message "Running '#{action}' for #{@name} #{@version}... "
|
335
|
+
end
|
336
|
+
|
337
|
+
if Process.respond_to?(:spawn) && ! RbConfig.respond_to?(:java)
|
338
|
+
args = [command].flatten + [{[:out, :err]=>[log_out, "a"]}]
|
339
|
+
pid = spawn(*args)
|
340
|
+
Process.wait(pid)
|
341
|
+
else
|
342
|
+
redirected = if command.kind_of?(Array)
|
343
|
+
%Q{#{command.map(&:shellescape).join(" ")} > #{log_out.shellescape} 2>&1}
|
344
|
+
else
|
345
|
+
%Q{#{command} > #{log_out.shellescape} 2>&1}
|
346
|
+
end
|
347
|
+
system redirected
|
348
|
+
end
|
349
|
+
|
350
|
+
if $?.success?
|
351
|
+
output "OK"
|
352
|
+
return true
|
353
|
+
else
|
354
|
+
if File.exist? log_out
|
355
|
+
output "ERROR, review '#{log_out}' to see what happened. Last lines are:"
|
356
|
+
output("=" * 72)
|
357
|
+
log_lines = File.readlines(log_out)
|
358
|
+
output(log_lines[-[log_lines.length, 20].min .. -1])
|
359
|
+
output("=" * 72)
|
360
|
+
end
|
361
|
+
raise "Failed to complete #{action} task"
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def newer?(target, checkpoint)
|
367
|
+
if (target && File.exist?(target)) && (checkpoint && File.exist?(checkpoint))
|
368
|
+
File.mtime(target) > File.mtime(checkpoint)
|
369
|
+
else
|
370
|
+
false
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
# print out a message with the logger
|
375
|
+
def message(text)
|
376
|
+
@logger.print text
|
377
|
+
@logger.flush
|
378
|
+
end
|
379
|
+
|
380
|
+
# print out a message using the logger but return to a new line
|
381
|
+
def output(text = "")
|
382
|
+
@logger.puts text
|
383
|
+
@logger.flush
|
384
|
+
end
|
385
|
+
|
386
|
+
# Slighly modified from RubyInstaller uri_ext, Rubinius configure
|
387
|
+
# and adaptations of Wayne's RailsInstaller
|
388
|
+
def download_file(url, full_path, count = 3)
|
389
|
+
return if File.exist?(full_path)
|
390
|
+
uri = URI.parse(url)
|
391
|
+
begin
|
392
|
+
case uri.scheme.downcase
|
393
|
+
when /ftp/
|
394
|
+
download_file_ftp(uri, full_path)
|
395
|
+
when /http|https/
|
396
|
+
download_file_http(url, full_path, count)
|
397
|
+
end
|
398
|
+
rescue Exception => e
|
399
|
+
File.unlink full_path if File.exist?(full_path)
|
400
|
+
output "ERROR: #{e.message}"
|
401
|
+
raise "Failed to complete download task"
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def download_file_http(url, full_path, count = 3)
|
406
|
+
filename = File.basename(full_path)
|
407
|
+
with_tempfile(filename, full_path) do |temp_file|
|
408
|
+
progress = 0
|
409
|
+
total = 0
|
410
|
+
params = {
|
411
|
+
"Accept-Encoding" => 'identity',
|
412
|
+
:content_length_proc => lambda{|length| total = length },
|
413
|
+
:progress_proc => lambda{|bytes|
|
414
|
+
new_progress = (bytes * 100) / total
|
415
|
+
message "\rDownloading %s (%3d%%) " % [filename, new_progress]
|
416
|
+
progress = new_progress
|
417
|
+
}
|
418
|
+
}
|
419
|
+
proxy_uri = URI.parse(url).scheme.downcase == 'https' ?
|
420
|
+
ENV["https_proxy"] :
|
421
|
+
ENV["http_proxy"]
|
422
|
+
if proxy_uri
|
423
|
+
_, userinfo, _p_host, _p_port = URI.split(proxy_uri)
|
424
|
+
if userinfo
|
425
|
+
proxy_user, proxy_pass = userinfo.split(/:/).map{|s| CGI.unescape(s) }
|
426
|
+
params[:proxy_http_basic_authentication] =
|
427
|
+
[proxy_uri, proxy_user, proxy_pass]
|
428
|
+
end
|
429
|
+
end
|
430
|
+
begin
|
431
|
+
OpenURI.open_uri(url, 'rb', params) do |io|
|
432
|
+
temp_file << io.read
|
433
|
+
end
|
434
|
+
output
|
435
|
+
rescue OpenURI::HTTPRedirect => redirect
|
436
|
+
raise "Too many redirections for the original URL, halting." if count <= 0
|
437
|
+
count = count - 1
|
438
|
+
return download_file(redirect.url, full_path, count - 1)
|
439
|
+
rescue => e
|
440
|
+
output e.message
|
441
|
+
return false
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def download_file_ftp(uri, full_path)
|
447
|
+
filename = File.basename(uri.path)
|
448
|
+
with_tempfile(filename, full_path) do |temp_file|
|
449
|
+
progress = 0
|
450
|
+
total = 0
|
451
|
+
params = {
|
452
|
+
:content_length_proc => lambda{|length| total = length },
|
453
|
+
:progress_proc => lambda{|bytes|
|
454
|
+
new_progress = (bytes * 100) / total
|
455
|
+
message "\rDownloading %s (%3d%%) " % [filename, new_progress]
|
456
|
+
progress = new_progress
|
457
|
+
}
|
458
|
+
}
|
459
|
+
if ENV["ftp_proxy"]
|
460
|
+
_, userinfo, _p_host, _p_port = URI.split(ENV['ftp_proxy'])
|
461
|
+
if userinfo
|
462
|
+
proxy_user, proxy_pass = userinfo.split(/:/).map{|s| CGI.unescape(s) }
|
463
|
+
params[:proxy_http_basic_authentication] =
|
464
|
+
[ENV['ftp_proxy'], proxy_user, proxy_pass]
|
465
|
+
end
|
466
|
+
end
|
467
|
+
OpenURI.open_uri(uri, 'rb', params) do |io|
|
468
|
+
temp_file << io.read
|
469
|
+
end
|
470
|
+
output
|
471
|
+
end
|
472
|
+
rescue Net::FTPError
|
473
|
+
return false
|
474
|
+
end
|
475
|
+
|
476
|
+
def with_tempfile(filename, full_path)
|
477
|
+
temp_file = Tempfile.new("download-#{filename}")
|
478
|
+
temp_file.binmode
|
479
|
+
yield temp_file
|
480
|
+
temp_file.close
|
481
|
+
File.unlink full_path if File.exist?(full_path)
|
482
|
+
FileUtils.mkdir_p File.dirname(full_path)
|
483
|
+
FileUtils.mv temp_file.path, full_path, :force => true
|
484
|
+
end
|
485
|
+
|
486
|
+
def gcc_cmd
|
487
|
+
cc = ENV["CC"] || RbConfig::CONFIG["CC"] || "gcc"
|
488
|
+
return cc.dup
|
489
|
+
end
|
490
|
+
|
491
|
+
def make_cmd
|
492
|
+
m = ENV['MAKE'] || ENV['make'] || 'make'
|
493
|
+
return m.dup
|
494
|
+
end
|
495
|
+
end
|