mini_portile 0.6.2 → 0.7.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 +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +15 -0
- data/{History.txt → CHANGELOG.md} +36 -14
- data/Gemfile +4 -0
- data/README.md +185 -0
- data/Rakefile +16 -44
- data/appveyor.yml +21 -0
- data/examples/.gitignore +2 -0
- data/examples/Rakefile +17 -3
- data/examples/libiconv-patches/1-avoid-gets-error.patch +16 -0
- data/lib/mini_portile.rb +2 -437
- data/lib/mini_portile/mini_portile.rb +494 -0
- data/lib/mini_portile/version.rb +3 -0
- data/mini_portile.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 +46 -0
- data/test/test_cook.rb +71 -0
- data/test/test_digest.rb +75 -0
- data/test/test_proxy.rb +124 -0
- metadata +92 -19
- data/README.rdoc +0 -169
@@ -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@
|
data/lib/mini_portile.rb
CHANGED
@@ -1,437 +1,2 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require 'net/https'
|
4
|
-
require 'net/ftp'
|
5
|
-
require 'fileutils'
|
6
|
-
require 'tempfile'
|
7
|
-
require 'digest/md5'
|
8
|
-
|
9
|
-
class MiniPortile
|
10
|
-
attr_reader :name, :version, :original_host
|
11
|
-
attr_writer :configure_options
|
12
|
-
attr_accessor :host, :files, :patch_files, :target, :logger
|
13
|
-
|
14
|
-
def initialize(name, version)
|
15
|
-
@name = name
|
16
|
-
@version = version
|
17
|
-
@target = 'ports'
|
18
|
-
@files = []
|
19
|
-
@patch_files = []
|
20
|
-
@logger = STDOUT
|
21
|
-
|
22
|
-
@original_host = @host = detect_host
|
23
|
-
end
|
24
|
-
|
25
|
-
def download
|
26
|
-
@files.each do |url|
|
27
|
-
filename = File.basename(url)
|
28
|
-
download_file(url, File.join(archives_path, filename))
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def extract
|
33
|
-
@files.each do |url|
|
34
|
-
filename = File.basename(url)
|
35
|
-
extract_file(File.join(archives_path, filename), tmp_path)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def patch
|
40
|
-
# Set GIT_DIR while appying patches to work around
|
41
|
-
# git-apply doing nothing when started within another
|
42
|
-
# git directory.
|
43
|
-
ENV['GIT_DIR'], old_git = '.', ENV['GIT_DIR']
|
44
|
-
begin
|
45
|
-
@patch_files.each do |full_path|
|
46
|
-
next unless File.exists?(full_path)
|
47
|
-
output "Running git apply with #{full_path}..."
|
48
|
-
execute('patch', %Q(git apply #{full_path}))
|
49
|
-
end
|
50
|
-
ensure
|
51
|
-
ENV['GIT_DIR'] = old_git
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def configure_options
|
56
|
-
@configure_options ||= configure_defaults
|
57
|
-
end
|
58
|
-
|
59
|
-
def configure
|
60
|
-
return if configured?
|
61
|
-
|
62
|
-
md5_file = File.join(tmp_path, 'configure.md5')
|
63
|
-
digest = Digest::MD5.hexdigest(computed_options)
|
64
|
-
File.open(md5_file, "w") { |f| f.write digest }
|
65
|
-
|
66
|
-
execute('configure', %Q(sh configure #{computed_options}))
|
67
|
-
end
|
68
|
-
|
69
|
-
def compile
|
70
|
-
execute('compile', make_cmd)
|
71
|
-
end
|
72
|
-
|
73
|
-
def install
|
74
|
-
return if installed?
|
75
|
-
execute('install', %Q(#{make_cmd} install))
|
76
|
-
end
|
77
|
-
|
78
|
-
def downloaded?
|
79
|
-
missing = @files.detect do |url|
|
80
|
-
filename = File.basename(url)
|
81
|
-
!File.exist?(File.join(archives_path, filename))
|
82
|
-
end
|
83
|
-
|
84
|
-
missing ? false : true
|
85
|
-
end
|
86
|
-
|
87
|
-
def configured?
|
88
|
-
configure = File.join(work_path, 'configure')
|
89
|
-
makefile = File.join(work_path, 'Makefile')
|
90
|
-
md5_file = File.join(tmp_path, 'configure.md5')
|
91
|
-
|
92
|
-
stored_md5 = File.exist?(md5_file) ? File.read(md5_file) : ""
|
93
|
-
current_md5 = Digest::MD5.hexdigest(computed_options)
|
94
|
-
|
95
|
-
(current_md5 == stored_md5) && newer?(makefile, configure)
|
96
|
-
end
|
97
|
-
|
98
|
-
def installed?
|
99
|
-
makefile = File.join(work_path, 'Makefile')
|
100
|
-
target_dir = Dir.glob("#{port_path}/*").find { |d| File.directory?(d) }
|
101
|
-
|
102
|
-
newer?(target_dir, makefile)
|
103
|
-
end
|
104
|
-
|
105
|
-
def cook
|
106
|
-
download unless downloaded?
|
107
|
-
extract
|
108
|
-
patch
|
109
|
-
configure unless configured?
|
110
|
-
compile
|
111
|
-
install unless installed?
|
112
|
-
|
113
|
-
return true
|
114
|
-
end
|
115
|
-
|
116
|
-
def activate
|
117
|
-
lib_path = File.join(port_path, "lib")
|
118
|
-
vars = {
|
119
|
-
'PATH' => File.join(port_path, 'bin'),
|
120
|
-
'CPATH' => File.join(port_path, 'include'),
|
121
|
-
'LIBRARY_PATH' => lib_path
|
122
|
-
}.reject { |env, path| !File.directory?(path) }
|
123
|
-
|
124
|
-
output "Activating #{@name} #{@version} (from #{port_path})..."
|
125
|
-
vars.each do |var, path|
|
126
|
-
full_path = File.expand_path(path)
|
127
|
-
|
128
|
-
# turn into a valid Windows path (if required)
|
129
|
-
full_path.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR
|
130
|
-
|
131
|
-
# save current variable value
|
132
|
-
old_value = ENV[var] || ''
|
133
|
-
|
134
|
-
unless old_value.include?(full_path)
|
135
|
-
ENV[var] = "#{full_path}#{File::PATH_SEPARATOR}#{old_value}"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# rely on LDFLAGS when cross-compiling
|
140
|
-
if File.exist?(lib_path) && (@host != @original_host)
|
141
|
-
full_path = File.expand_path(lib_path)
|
142
|
-
|
143
|
-
old_value = ENV.fetch("LDFLAGS", "")
|
144
|
-
|
145
|
-
unless old_value.include?(full_path)
|
146
|
-
ENV["LDFLAGS"] = "-L#{full_path} #{old_value}".strip
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def path
|
152
|
-
File.expand_path(port_path)
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
|
157
|
-
def tmp_path
|
158
|
-
"tmp/#{@host}/ports/#{@name}/#{@version}"
|
159
|
-
end
|
160
|
-
|
161
|
-
def port_path
|
162
|
-
"#{@target}/#{@host}/#{@name}/#{@version}"
|
163
|
-
end
|
164
|
-
|
165
|
-
def archives_path
|
166
|
-
"#{@target}/archives"
|
167
|
-
end
|
168
|
-
|
169
|
-
def work_path
|
170
|
-
Dir.glob("#{tmp_path}/*").find { |d| File.directory?(d) }
|
171
|
-
end
|
172
|
-
|
173
|
-
def configure_defaults
|
174
|
-
[
|
175
|
-
"--host=#{@host}", # build for specific target (host)
|
176
|
-
"--enable-static", # build static library
|
177
|
-
"--disable-shared" # disable generation of shared object
|
178
|
-
]
|
179
|
-
end
|
180
|
-
|
181
|
-
def configure_prefix
|
182
|
-
"--prefix=#{File.expand_path(port_path)}"
|
183
|
-
end
|
184
|
-
|
185
|
-
def computed_options
|
186
|
-
[
|
187
|
-
configure_options, # customized or default options
|
188
|
-
configure_prefix, # installation target
|
189
|
-
].flatten.join(' ')
|
190
|
-
end
|
191
|
-
|
192
|
-
def log_file(action)
|
193
|
-
File.join(tmp_path, "#{action}.log")
|
194
|
-
end
|
195
|
-
|
196
|
-
def tar_exe
|
197
|
-
@@tar_exe ||= begin
|
198
|
-
%w[gtar bsdtar tar basic-bsdtar].find { |c|
|
199
|
-
which(c)
|
200
|
-
}
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def tar_compression_switch(filename)
|
205
|
-
case File.extname(filename)
|
206
|
-
when '.gz', '.tgz'
|
207
|
-
'z'
|
208
|
-
when '.bz2', '.tbz2'
|
209
|
-
'j'
|
210
|
-
when '.Z'
|
211
|
-
'Z'
|
212
|
-
else
|
213
|
-
''
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
# From: http://stackoverflow.com/a/5471032/7672
|
218
|
-
# Thanks, Mislav!
|
219
|
-
#
|
220
|
-
# Cross-platform way of finding an executable in the $PATH.
|
221
|
-
#
|
222
|
-
# which('ruby') #=> /usr/bin/ruby
|
223
|
-
def which(cmd)
|
224
|
-
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
225
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
226
|
-
exts.each { |ext|
|
227
|
-
exe = File.join(path, "#{cmd}#{ext}")
|
228
|
-
return exe if File.executable? exe
|
229
|
-
}
|
230
|
-
end
|
231
|
-
return nil
|
232
|
-
end
|
233
|
-
|
234
|
-
def detect_host
|
235
|
-
return @detect_host if defined?(@detect_host)
|
236
|
-
|
237
|
-
begin
|
238
|
-
ENV["LC_ALL"], old_lc_all = "C", ENV["LC_ALL"]
|
239
|
-
|
240
|
-
output = `#{gcc_cmd} -v 2>&1`
|
241
|
-
if m = output.match(/^Target\: (.*)$/)
|
242
|
-
@detect_host = m[1]
|
243
|
-
end
|
244
|
-
|
245
|
-
@detect_host
|
246
|
-
ensure
|
247
|
-
ENV["LC_ALL"] = old_lc_all
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
def extract_file(file, target)
|
252
|
-
filename = File.basename(file)
|
253
|
-
FileUtils.mkdir_p target
|
254
|
-
|
255
|
-
message "Extracting #{filename} into #{target}... "
|
256
|
-
result = `#{tar_exe} #{tar_compression_switch(filename)}xf "#{file}" -C "#{target}" 2>&1`
|
257
|
-
if $?.success?
|
258
|
-
output "OK"
|
259
|
-
else
|
260
|
-
output "ERROR"
|
261
|
-
output result
|
262
|
-
raise "Failed to complete extract task"
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def execute(action, command)
|
267
|
-
log = log_file(action)
|
268
|
-
log_out = File.expand_path(log)
|
269
|
-
redirected = command << " >#{log_out} 2>&1"
|
270
|
-
|
271
|
-
Dir.chdir work_path do
|
272
|
-
message "Running '#{action}' for #{@name} #{@version}... "
|
273
|
-
system redirected
|
274
|
-
if $?.success?
|
275
|
-
output "OK"
|
276
|
-
return true
|
277
|
-
else
|
278
|
-
output "ERROR, review '#{log_out}' to see what happened."
|
279
|
-
raise "Failed to complete #{action} task"
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
def newer?(target, checkpoint)
|
285
|
-
if (target && File.exist?(target)) && (checkpoint && File.exist?(checkpoint))
|
286
|
-
File.mtime(target) > File.mtime(checkpoint)
|
287
|
-
else
|
288
|
-
false
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
# print out a message with the logger
|
293
|
-
def message(text)
|
294
|
-
@logger.print text
|
295
|
-
@logger.flush
|
296
|
-
end
|
297
|
-
|
298
|
-
# print out a message using the logger but return to a new line
|
299
|
-
def output(text = "")
|
300
|
-
@logger.puts text
|
301
|
-
@logger.flush
|
302
|
-
end
|
303
|
-
|
304
|
-
# Slighly modified from RubyInstaller uri_ext, Rubinius configure
|
305
|
-
# and adaptations of Wayne's RailsInstaller
|
306
|
-
def download_file(url, full_path, count = 3)
|
307
|
-
return if File.exist?(full_path)
|
308
|
-
uri = URI.parse(url)
|
309
|
-
begin
|
310
|
-
case uri.scheme.downcase
|
311
|
-
when /ftp/
|
312
|
-
download_file_ftp(uri, full_path)
|
313
|
-
when /http|https/
|
314
|
-
download_file_http(url, full_path, count)
|
315
|
-
end
|
316
|
-
rescue Exception => e
|
317
|
-
File.unlink full_path if File.exists?(full_path)
|
318
|
-
output "ERROR: #{e.message}"
|
319
|
-
raise "Failed to complete download task"
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
def download_file_http(url, full_path, count = 3)
|
324
|
-
filename = File.basename(full_path)
|
325
|
-
uri = URI.parse(url)
|
326
|
-
|
327
|
-
if ENV['http_proxy']
|
328
|
-
_, userinfo, p_host, p_port = URI.split(ENV['http_proxy'])
|
329
|
-
proxy_user, proxy_pass = userinfo.split(/:/) if userinfo
|
330
|
-
http = Net::HTTP.new(uri.host, uri.port, p_host, p_port, proxy_user, proxy_pass)
|
331
|
-
else
|
332
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
333
|
-
|
334
|
-
if URI::HTTPS === uri
|
335
|
-
http.use_ssl = true
|
336
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
337
|
-
|
338
|
-
store = OpenSSL::X509::Store.new
|
339
|
-
|
340
|
-
# Auto-include system-provided certificates
|
341
|
-
store.set_default_paths
|
342
|
-
|
343
|
-
if ENV.has_key?("SSL_CERT_FILE") && File.exist?(ENV["SSL_CERT_FILE"])
|
344
|
-
store.add_file ENV["SSL_CERT_FILE"]
|
345
|
-
end
|
346
|
-
|
347
|
-
http.cert_store = store
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
message "Downloading #{filename} "
|
352
|
-
http.start do |h|
|
353
|
-
h.request_get(uri.path, 'Accept-Encoding' => 'identity') do |response|
|
354
|
-
case response
|
355
|
-
when Net::HTTPNotFound
|
356
|
-
output "404 - Not Found"
|
357
|
-
return false
|
358
|
-
|
359
|
-
when Net::HTTPClientError
|
360
|
-
output "Error: Client Error: #{response.inspect}"
|
361
|
-
return false
|
362
|
-
|
363
|
-
when Net::HTTPRedirection
|
364
|
-
raise "Too many redirections for the original URL, halting." if count <= 0
|
365
|
-
url = response["location"]
|
366
|
-
return download_file(url, full_path, count - 1)
|
367
|
-
|
368
|
-
when Net::HTTPOK
|
369
|
-
return with_tempfile(filename, full_path) do |temp_file|
|
370
|
-
size = 0
|
371
|
-
progress = 0
|
372
|
-
total = response.header["Content-Length"].to_i
|
373
|
-
response.read_body do |chunk|
|
374
|
-
temp_file << chunk
|
375
|
-
size += chunk.size
|
376
|
-
new_progress = (size * 100) / total
|
377
|
-
unless new_progress == progress
|
378
|
-
message "\rDownloading %s (%3d%%) " % [filename, new_progress]
|
379
|
-
end
|
380
|
-
progress = new_progress
|
381
|
-
end
|
382
|
-
output
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
end
|
387
|
-
end
|
388
|
-
|
389
|
-
def download_file_ftp(uri, full_path)
|
390
|
-
filename = File.basename(uri.path)
|
391
|
-
with_tempfile(filename, full_path) do |temp_file|
|
392
|
-
size = 0
|
393
|
-
progress = 0
|
394
|
-
Net::FTP.open(uri.host, uri.user, uri.password) do |ftp|
|
395
|
-
ftp.passive = true
|
396
|
-
ftp.login
|
397
|
-
remote_dir = File.dirname(uri.path)
|
398
|
-
ftp.chdir(remote_dir) unless remote_dir == '.'
|
399
|
-
total = ftp.size(filename)
|
400
|
-
ftp.getbinaryfile(filename, temp_file.path, 8192) do |chunk|
|
401
|
-
# Ruby 1.8.7 already wrote the chunk into the file
|
402
|
-
unless RUBY_VERSION < "1.9"
|
403
|
-
temp_file << chunk
|
404
|
-
end
|
405
|
-
|
406
|
-
size += chunk.size
|
407
|
-
new_progress = (size * 100) / total
|
408
|
-
unless new_progress == progress
|
409
|
-
message "\rDownloading %s (%3d%%) " % [filename, new_progress]
|
410
|
-
end
|
411
|
-
progress = new_progress
|
412
|
-
end
|
413
|
-
end
|
414
|
-
output
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
def with_tempfile(filename, full_path)
|
419
|
-
temp_file = Tempfile.new("download-#{filename}")
|
420
|
-
temp_file.binmode
|
421
|
-
yield temp_file
|
422
|
-
temp_file.close
|
423
|
-
File.unlink full_path if File.exists?(full_path)
|
424
|
-
FileUtils.mkdir_p File.dirname(full_path)
|
425
|
-
FileUtils.mv temp_file.path, full_path, :force => true
|
426
|
-
end
|
427
|
-
|
428
|
-
def gcc_cmd
|
429
|
-
cc = ENV["CC"] || RbConfig::CONFIG["CC"] || "gcc"
|
430
|
-
return cc.dup
|
431
|
-
end
|
432
|
-
|
433
|
-
def make_cmd
|
434
|
-
m = ENV['MAKE'] || ENV['make'] || 'make'
|
435
|
-
return m.dup
|
436
|
-
end
|
437
|
-
end
|
1
|
+
require "mini_portile/version"
|
2
|
+
require "mini_portile/mini_portile"
|