ruby-mp3info 0.6.16 → 0.7
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.
- data/History.txt +6 -0
- data/Manifest.txt +0 -1
- data/README.txt +7 -9
- data/Rakefile +1 -1
- data/lib/mp3info.rb +17 -12
- data/lib/mp3info/extension_modules.rb +46 -4
- data/lib/mp3info/id3v2.rb +102 -74
- data/test/test_ruby-mp3info.rb +57 -100
- metadata +47 -55
- data/install.rb +0 -1022
data/test/test_ruby-mp3info.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#!/usr/bin/env
|
2
|
-
#
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
3
|
|
4
4
|
$:.unshift("lib/")
|
5
5
|
|
@@ -10,7 +10,7 @@ require "tempfile"
|
|
10
10
|
require "zlib"
|
11
11
|
require "yaml"
|
12
12
|
|
13
|
-
system("which id3v2 > /dev/null")
|
13
|
+
GOT_ID3V2 = system("which id3v2 > /dev/null")
|
14
14
|
|
15
15
|
class Mp3InfoTest < Test::Unit::TestCase
|
16
16
|
|
@@ -36,20 +36,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
36
36
|
"genre" => 233
|
37
37
|
}
|
38
38
|
|
39
|
-
FIXTURES = YAML::load_file( File.join(File.dirname(__FILE__), "fixtures.yml") )
|
40
|
-
|
41
39
|
def setup
|
42
|
-
# Command to create a gzip'ed dummy MP3
|
43
|
-
# $ dd if=/dev/zero bs=1024 count=15 | \
|
44
|
-
# lame --quiet --preset cbr 128 -r -s 44.1 --bitwidth 16 - - | \
|
45
|
-
# ruby -rbase64 -rzlib -ryaml -e 'print(Zlib::Deflate.deflate($stdin.read)'
|
46
|
-
# vbr:
|
47
|
-
# $ dd if=/dev/zero of=#{tempfile.path} bs=1024 count=30000 |
|
48
|
-
# system("lame -h -v -b 112 -r -s 44.1 --bitwidth 16 - /tmp/vbr.mp3
|
49
|
-
@valid_mp3, @valid_mp3_2_2, @vbr_mp3 = %w{empty_mp3 2_2_tagged vbr}.collect do |fixture_key|
|
50
|
-
Zlib::Inflate.inflate(FIXTURES[fixture_key])
|
51
|
-
end
|
52
|
-
|
53
40
|
@tag = {
|
54
41
|
"title" => "title",
|
55
42
|
"artist" => "artist",
|
@@ -60,7 +47,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
60
47
|
"genre_s" => "Blues",
|
61
48
|
"tracknum" => 36
|
62
49
|
}
|
63
|
-
|
50
|
+
load_fixture_to_temp_file("empty_mp3")
|
64
51
|
end
|
65
52
|
|
66
53
|
def teardown
|
@@ -94,7 +81,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
94
81
|
end
|
95
82
|
|
96
83
|
def test_vbr_mp3_length
|
97
|
-
|
84
|
+
load_fixture_to_temp_file("vbr")
|
98
85
|
|
99
86
|
Mp3Info.open(TEMP_FILE) do |info|
|
100
87
|
assert(info.vbr)
|
@@ -145,8 +132,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
145
132
|
|
146
133
|
def id3_test(tag_str, valid_tag)
|
147
134
|
tag = "TAG" + tag_str
|
148
|
-
File.open(TEMP_FILE, "
|
149
|
-
f.write(@valid_mp3)
|
135
|
+
File.open(TEMP_FILE, "a") do |f|
|
150
136
|
f.write(tag)
|
151
137
|
end
|
152
138
|
assert(Mp3Info.hastag1?(TEMP_FILE))
|
@@ -156,7 +142,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
156
142
|
end
|
157
143
|
|
158
144
|
def test_removetag2
|
159
|
-
w = write_tag2_to_temp_file(
|
145
|
+
w = write_tag2_to_temp_file("TIT2" => "sdfqdsf")
|
160
146
|
|
161
147
|
assert( Mp3Info.hastag2?(TEMP_FILE) )
|
162
148
|
Mp3Info.removetag2(TEMP_FILE)
|
@@ -200,7 +186,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
200
186
|
|
201
187
|
def test_id3v2_version
|
202
188
|
written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
|
203
|
-
assert_equal( "2
|
189
|
+
assert_equal( "2.3.0", written_tag.version )
|
204
190
|
end
|
205
191
|
|
206
192
|
def test_id3v2_methods
|
@@ -214,38 +200,42 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
214
200
|
end
|
215
201
|
|
216
202
|
def test_id3v2_basic
|
217
|
-
|
218
|
-
assert_equal(DUMMY_TAG2,
|
219
|
-
id3v2_prog_test(DUMMY_TAG2,
|
203
|
+
written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
|
204
|
+
assert_equal(DUMMY_TAG2, written_tag)
|
205
|
+
id3v2_prog_test(DUMMY_TAG2, written_tag)
|
220
206
|
end
|
221
207
|
|
222
208
|
#test the tag with the "id3v2" program
|
223
209
|
def id3v2_prog_test(tag, written_tag)
|
224
|
-
return
|
225
|
-
return if `which id3v2`.empty?
|
210
|
+
return unless GOT_ID3V2
|
226
211
|
start = false
|
227
212
|
id3v2_output = {}
|
228
|
-
|
213
|
+
=begin
|
214
|
+
id3v2 tag info for test/test_mp3info.mp3:
|
215
|
+
COMM (Comments): (~)[ENG]:
|
216
|
+
test/test_mp3info.mp3: No ID3v1 tag
|
217
|
+
=end
|
218
|
+
raw_output = `id3v2 -l #{TEMP_FILE}`
|
219
|
+
raw_output.split(/\n/).each do |line|
|
229
220
|
if line =~ /^id3v2 tag info/
|
230
221
|
start = true
|
231
222
|
next
|
232
223
|
end
|
233
224
|
next unless start
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
225
|
+
if match = /^(.{4}) \(.+\): (.+)$/.match(line)
|
226
|
+
k, v = match[1, 2]
|
227
|
+
case k
|
228
|
+
#COMM (Comments): ()[spa]: fmg
|
229
|
+
when "COMM"
|
230
|
+
v.sub!(/\(\)\[.{3}\]: (.+)/, '\1')
|
231
|
+
end
|
232
|
+
id3v2_output[k] = v
|
239
233
|
end
|
240
|
-
id3v2_output[k] = v
|
241
234
|
end
|
242
235
|
|
243
236
|
assert_equal( id3v2_output, written_tag, "id3v2 program output doesn't match")
|
244
237
|
end
|
245
238
|
|
246
|
-
def test_id3v2_trash
|
247
|
-
end
|
248
|
-
|
249
239
|
def test_id3v2_complex
|
250
240
|
tag = {}
|
251
241
|
#ID3v2::TAGS.keys.each do |k|
|
@@ -262,16 +252,13 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
262
252
|
assert_equal(tag, write_tag2_to_temp_file(tag))
|
263
253
|
end
|
264
254
|
|
265
|
-
def test_infinite_loop_on_seek_to_v2_end
|
266
|
-
|
267
|
-
end
|
268
|
-
|
269
255
|
def test_leading_char_gets_chopped
|
270
256
|
tag2 = DUMMY_TAG2.dup
|
271
257
|
tag2["WOAR"] = "http://foo.bar"
|
272
258
|
w = write_tag2_to_temp_file(tag2)
|
273
259
|
assert_equal("http://foo.bar", w["WOAR"])
|
274
260
|
|
261
|
+
return unless GOT_ID3V2
|
275
262
|
system(%(id3v2 --WOAR "http://foo.bar" "#{TEMP_FILE}"))
|
276
263
|
|
277
264
|
Mp3Info.open(TEMP_FILE) do |mp3|
|
@@ -280,7 +267,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
280
267
|
end
|
281
268
|
|
282
269
|
def test_reading2_2_tags
|
283
|
-
|
270
|
+
load_fixture_to_temp_file("2_2_tagged")
|
284
271
|
|
285
272
|
Mp3Info.open(TEMP_FILE) do |mp3|
|
286
273
|
assert_equal "2.2.0", mp3.tag2.version
|
@@ -313,7 +300,8 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
313
300
|
end
|
314
301
|
|
315
302
|
def test_writing_universal_tag_from_2_2_tags
|
316
|
-
|
303
|
+
load_fixture_to_temp_file("2_2_tagged")
|
304
|
+
|
317
305
|
Mp3Info.open(TEMP_FILE) do |mp3|
|
318
306
|
mp3.tag.artist = "toto"
|
319
307
|
mp3.tag.comments = "comments"
|
@@ -352,7 +340,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
352
340
|
Mp3Info.open(fn) do |mp3|
|
353
341
|
mp3.tag.title = fn
|
354
342
|
mp3.flush
|
355
|
-
if RUBY_VERSION
|
343
|
+
if RUBY_VERSION[0..2] == "1.8"
|
356
344
|
assert_equal fn, mp3.tag.title
|
357
345
|
else
|
358
346
|
assert_equal fn, mp3.tag.title.force_encoding("utf-8")
|
@@ -363,58 +351,6 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
363
351
|
end
|
364
352
|
end
|
365
353
|
|
366
|
-
def test_validity_of_id3v2_options
|
367
|
-
info = Mp3Info.new(TEMP_FILE)
|
368
|
-
expected_hash = { :lang => "ENG", :encoding => "iso-8859-1" }
|
369
|
-
assert_equal( expected_hash, info.tag2.options)
|
370
|
-
|
371
|
-
assert_raises(ArgumentError) do
|
372
|
-
Mp3Info.new(TEMP_FILE, :encoding => "bad encoding")
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
def test_encoding_read
|
377
|
-
Mp3Info.open(TEMP_FILE) do |mp3|
|
378
|
-
mp3.tag2['TEST'] = "all\xe9"
|
379
|
-
end
|
380
|
-
|
381
|
-
Mp3Info.open(TEMP_FILE, :encoding => "utf-8") do |mp3|
|
382
|
-
assert_equal "allé", mp3.tag2['TEST']
|
383
|
-
end
|
384
|
-
|
385
|
-
Mp3Info.open(TEMP_FILE, :encoding => "iso-8859-1") do |mp3|
|
386
|
-
if RUBY_VERSION < "1.9.0"
|
387
|
-
assert_equal "all\xe9", mp3.tag2['TEST']
|
388
|
-
else
|
389
|
-
assert_equal "all\xe9".force_encoding("binary"), mp3.tag2['TEST']
|
390
|
-
end
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
def test_encoding_write
|
395
|
-
Mp3Info.open(TEMP_FILE, :encoding => 'utf-8') do |mp3|
|
396
|
-
mp3.tag2['TEST'] = "all\xc3\xa9"
|
397
|
-
end
|
398
|
-
|
399
|
-
Mp3Info.open(TEMP_FILE, :encoding => "iso-8859-1") do |mp3|
|
400
|
-
if RUBY_VERSION < "1.9.0"
|
401
|
-
assert_equal "all\xe9", mp3.tag2['TEST']
|
402
|
-
else
|
403
|
-
assert_equal "all\xe9".force_encoding("iso-8859-1"), mp3.tag2['TEST']
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
=begin
|
409
|
-
def test_should_raises_exception_when_writing_badly_encoded_frames
|
410
|
-
assert_raises(Iconv::Failure) do
|
411
|
-
Mp3Info.open(TEMP_FILE, :encoding => 'utf-8') do |mp3|
|
412
|
-
mp3.tag2['TEST'] = "all\xc3"
|
413
|
-
end
|
414
|
-
end
|
415
|
-
end
|
416
|
-
=end
|
417
|
-
|
418
354
|
def test_audio_content
|
419
355
|
require "digest/md5"
|
420
356
|
|
@@ -441,7 +377,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
441
377
|
end
|
442
378
|
|
443
379
|
def test_audio_content_problematic
|
444
|
-
|
380
|
+
load_fixture_to_temp_file("audio_content_fixture", false)
|
445
381
|
Mp3Info.open(TEMP_FILE) do |mp3|
|
446
382
|
expected_pos = 150
|
447
383
|
audio_content_pos, audio_content_size = mp3.audio_content
|
@@ -452,9 +388,7 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
452
388
|
|
453
389
|
def test_headerless_vbr_file
|
454
390
|
mp3_length = 3
|
455
|
-
|
456
|
-
system("dd if=/dev/urandom bs=44100 count=#{mp3_length*4} 2>/dev/null | \
|
457
|
-
lame -v -m s --vbr-new --preset 128 -r -s 44.1 --bitwidth 16 - - > #{TEMP_FILE} 2>/dev/null")
|
391
|
+
load_fixture_to_temp_file("small_vbr_mp3")
|
458
392
|
|
459
393
|
Mp3Info.open(TEMP_FILE) do |mp3|
|
460
394
|
assert mp3.vbr
|
@@ -555,6 +489,29 @@ class Mp3InfoTest < Test::Unit::TestCase
|
|
555
489
|
io
|
556
490
|
end
|
557
491
|
|
492
|
+
FIXTURES = YAML::load_file( File.join(File.dirname(__FILE__), "fixtures.yml") )
|
493
|
+
|
494
|
+
def load_fixture_to_temp_file(fixture_key, zlibed = true)
|
495
|
+
# Command to create a gzip'ed dummy MP3
|
496
|
+
# $ dd if=/dev/zero bs=1024 count=15 | \
|
497
|
+
# lame --quiet --preset cbr 128 -r -s 44.1 --bitwidth 16 - - | \
|
498
|
+
# ruby -rbase64 -rzlib -ryaml -e 'print(Zlib::Deflate.deflate($stdin.read)'
|
499
|
+
# vbr:
|
500
|
+
# $ dd if=/dev/zero of=#{tempfile.path} bs=1024 count=30000 |
|
501
|
+
# system("lame -h -v -b 112 -r -s 44.1 --bitwidth 16 - /tmp/vbr.mp3
|
502
|
+
#
|
503
|
+
# this will generate a #{mp3_length} sec mp3 file (44100hz*16bit*2channels) = 60/4 = 15
|
504
|
+
# system("dd if=/dev/urandom bs=44100 count=#{mp3_length*4} 2>/dev/null | \
|
505
|
+
# lame -v -m s --vbr-new --preset 128 -r -s 44.1 --bitwidth 16 - - > #{TEMP_FILE} 2>/dev/null")
|
506
|
+
content = FIXTURES[fixture_key]
|
507
|
+
if zlibed
|
508
|
+
content = Zlib::Inflate.inflate(content)
|
509
|
+
end
|
510
|
+
|
511
|
+
File.open(TEMP_FILE, "w") do |f|
|
512
|
+
f.write(content)
|
513
|
+
end
|
514
|
+
end
|
558
515
|
=begin
|
559
516
|
|
560
517
|
def test_encoder
|
metadata
CHANGED
@@ -1,94 +1,86 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-mp3info
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.7'
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 6
|
9
|
-
- 16
|
10
|
-
version: 0.6.16
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Guillaume Pierronnet
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
12
|
+
date: 2012-03-02 00:00:00.000000000 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rdoc
|
17
|
+
requirement: &79955210 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3.10'
|
23
|
+
type: :development
|
22
24
|
prerelease: false
|
23
|
-
|
25
|
+
version_requirements: *79955210
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: hoe
|
28
|
+
requirement: &79954780 !ruby/object:Gem::Requirement
|
24
29
|
none: false
|
25
|
-
requirements:
|
30
|
+
requirements:
|
26
31
|
- - ~>
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
segments:
|
30
|
-
- 2
|
31
|
-
- 10
|
32
|
-
version: "2.10"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.12'
|
33
34
|
type: :development
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
mp3 files.
|
38
|
-
email:
|
39
|
-
- moumar@rubyforge.org
|
40
|
-
executables: []
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *79954780
|
37
|
+
description: ! 'ruby-mp3info read low-level informations and manipulate tags on
|
41
38
|
|
39
|
+
mp3 files.'
|
40
|
+
email:
|
41
|
+
- guillaume.pierronnet@gmail.com
|
42
|
+
executables: []
|
42
43
|
extensions: []
|
43
|
-
|
44
|
-
extra_rdoc_files:
|
44
|
+
extra_rdoc_files:
|
45
45
|
- History.txt
|
46
46
|
- Manifest.txt
|
47
47
|
- README.txt
|
48
|
-
files:
|
48
|
+
files:
|
49
49
|
- History.txt
|
50
50
|
- Manifest.txt
|
51
51
|
- README.txt
|
52
52
|
- Rakefile
|
53
|
-
- install.rb
|
54
53
|
- lib/mp3info.rb
|
55
54
|
- lib/mp3info/extension_modules.rb
|
56
55
|
- lib/mp3info/id3v2.rb
|
57
56
|
- test/test_ruby-mp3info.rb
|
58
57
|
- .gemtest
|
58
|
+
has_rdoc: true
|
59
59
|
homepage: http://github.com/moumar/ruby-mp3info
|
60
60
|
licenses: []
|
61
|
-
|
62
61
|
post_install_message:
|
63
|
-
rdoc_options:
|
62
|
+
rdoc_options:
|
64
63
|
- --main
|
65
64
|
- README.txt
|
66
|
-
require_paths:
|
65
|
+
require_paths:
|
67
66
|
- lib
|
68
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
68
|
none: false
|
70
|
-
requirements:
|
71
|
-
- -
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
|
75
|
-
- 0
|
76
|
-
version: "0"
|
77
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
74
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
segments:
|
84
|
-
- 0
|
85
|
-
version: "0"
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
86
79
|
requirements: []
|
87
|
-
|
88
80
|
rubyforge_project: ruby-mp3info
|
89
|
-
rubygems_version: 1.
|
81
|
+
rubygems_version: 1.6.2
|
90
82
|
signing_key:
|
91
83
|
specification_version: 3
|
92
84
|
summary: ruby-mp3info read low-level informations and manipulate tags on mp3 files.
|
93
|
-
test_files:
|
85
|
+
test_files:
|
94
86
|
- test/test_ruby-mp3info.rb
|
data/install.rb
DELETED
@@ -1,1022 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# This file is automatically generated. DO NOT MODIFY!
|
3
|
-
#
|
4
|
-
# install.rb
|
5
|
-
#
|
6
|
-
# Copyright (c) 2000-2002 Minero Aoki <aamine@loveruby.net>
|
7
|
-
#
|
8
|
-
# This program is free software.
|
9
|
-
# You can distribute/modify this program under the terms of
|
10
|
-
# the GNU Lesser General Public License version 2.
|
11
|
-
#
|
12
|
-
|
13
|
-
### begin compat.rb
|
14
|
-
|
15
|
-
unless Enumerable.instance_methods.include? 'inject'
|
16
|
-
module Enumerable
|
17
|
-
def inject( result )
|
18
|
-
each do |i|
|
19
|
-
result = yield(result, i)
|
20
|
-
end
|
21
|
-
result
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def File.read_all( fname )
|
27
|
-
File.open(fname, 'rb') {|f| return f.read }
|
28
|
-
end
|
29
|
-
|
30
|
-
def File.write( fname, str )
|
31
|
-
File.open(fname, 'wb') {|f| f.write str }
|
32
|
-
end
|
33
|
-
|
34
|
-
### end compat.rb
|
35
|
-
### begin config.rb
|
36
|
-
|
37
|
-
if i = ARGV.index(/\A--rbconfig=/)
|
38
|
-
file = $'
|
39
|
-
ARGV.delete_at(i)
|
40
|
-
require file
|
41
|
-
else
|
42
|
-
require 'rbconfig'
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
class ConfigTable
|
47
|
-
|
48
|
-
c = ::Config::CONFIG
|
49
|
-
|
50
|
-
rubypath = c['bindir'] + '/' + c['ruby_install_name']
|
51
|
-
|
52
|
-
major = c['MAJOR'].to_i
|
53
|
-
minor = c['MINOR'].to_i
|
54
|
-
teeny = c['TEENY'].to_i
|
55
|
-
version = "#{major}.#{minor}"
|
56
|
-
|
57
|
-
# ruby ver. >= 1.4.4?
|
58
|
-
newpath_p = ((major >= 2) or
|
59
|
-
((major == 1) and
|
60
|
-
((minor >= 5) or
|
61
|
-
((minor == 4) and (teeny >= 4)))))
|
62
|
-
|
63
|
-
re = Regexp.new('\A' + Regexp.quote(c['prefix']))
|
64
|
-
subprefix = lambda {|path|
|
65
|
-
re === path and path.sub(re, '$prefix')
|
66
|
-
}
|
67
|
-
|
68
|
-
if c['rubylibdir']
|
69
|
-
# V < 1.6.3
|
70
|
-
stdruby = subprefix.call(c['rubylibdir'])
|
71
|
-
siteruby = subprefix.call(c['sitedir'])
|
72
|
-
versite = subprefix.call(c['sitelibdir'])
|
73
|
-
sodir = subprefix.call(c['sitearchdir'])
|
74
|
-
elsif newpath_p
|
75
|
-
# 1.4.4 <= V <= 1.6.3
|
76
|
-
stdruby = "$prefix/lib/ruby/#{version}"
|
77
|
-
siteruby = subprefix.call(c['sitedir'])
|
78
|
-
versite = siteruby + '/' + version
|
79
|
-
sodir = "$site-ruby/#{c['arch']}"
|
80
|
-
else
|
81
|
-
# V < 1.4.4
|
82
|
-
stdruby = "$prefix/lib/ruby/#{version}"
|
83
|
-
siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
|
84
|
-
versite = siteruby
|
85
|
-
sodir = "$site-ruby/#{c['arch']}"
|
86
|
-
end
|
87
|
-
|
88
|
-
DESCRIPTER = [
|
89
|
-
[ 'prefix', [ c['prefix'],
|
90
|
-
'path',
|
91
|
-
'path prefix of target environment' ] ],
|
92
|
-
[ 'std-ruby', [ stdruby,
|
93
|
-
'path',
|
94
|
-
'the directory for standard ruby libraries' ] ],
|
95
|
-
[ 'site-ruby-common', [ siteruby,
|
96
|
-
'path',
|
97
|
-
'the directory for version-independent non-standard ruby libraries' ] ],
|
98
|
-
[ 'site-ruby', [ versite,
|
99
|
-
'path',
|
100
|
-
'the directory for non-standard ruby libraries' ] ],
|
101
|
-
[ 'bin-dir', [ '$prefix/bin',
|
102
|
-
'path',
|
103
|
-
'the directory for commands' ] ],
|
104
|
-
[ 'rb-dir', [ '$site-ruby',
|
105
|
-
'path',
|
106
|
-
'the directory for ruby scripts' ] ],
|
107
|
-
[ 'so-dir', [ sodir,
|
108
|
-
'path',
|
109
|
-
'the directory for ruby extentions' ] ],
|
110
|
-
[ 'data-dir', [ '$prefix/share',
|
111
|
-
'path',
|
112
|
-
'the directory for shared data' ] ],
|
113
|
-
[ 'ruby-path', [ rubypath,
|
114
|
-
'path',
|
115
|
-
'path to set to #! line' ] ],
|
116
|
-
[ 'ruby-prog', [ rubypath,
|
117
|
-
'name',
|
118
|
-
'the ruby program using for installation' ] ],
|
119
|
-
[ 'make-prog', [ 'make',
|
120
|
-
'name',
|
121
|
-
'the make program to compile ruby extentions' ] ],
|
122
|
-
[ 'without-ext', [ 'no',
|
123
|
-
'yes/no',
|
124
|
-
'does not compile/install ruby extentions' ] ]
|
125
|
-
]
|
126
|
-
|
127
|
-
SAVE_FILE = 'config.save'
|
128
|
-
|
129
|
-
def ConfigTable.each_name( &block )
|
130
|
-
keys().each(&block)
|
131
|
-
end
|
132
|
-
|
133
|
-
def ConfigTable.keys
|
134
|
-
DESCRIPTER.collect {|k,*dummy| k }
|
135
|
-
end
|
136
|
-
|
137
|
-
def ConfigTable.each_definition( &block )
|
138
|
-
DESCRIPTER.each(&block)
|
139
|
-
end
|
140
|
-
|
141
|
-
def ConfigTable.get_entry( name )
|
142
|
-
name, ent = DESCRIPTER.assoc(name)
|
143
|
-
ent
|
144
|
-
end
|
145
|
-
|
146
|
-
def ConfigTable.get_entry!( name )
|
147
|
-
get_entry(name) or raise ArgumentError, "no such config: #{name}"
|
148
|
-
end
|
149
|
-
|
150
|
-
def ConfigTable.add_entry( name, vals )
|
151
|
-
ConfigTable::DESCRIPTER.push [name,vals]
|
152
|
-
end
|
153
|
-
|
154
|
-
def ConfigTable.remove_entry( name )
|
155
|
-
get_entry name or raise ArgumentError, "no such config: #{name}"
|
156
|
-
DESCRIPTER.delete_if {|n,arr| n == name }
|
157
|
-
end
|
158
|
-
|
159
|
-
def ConfigTable.config_key?( name )
|
160
|
-
get_entry(name) ? true : false
|
161
|
-
end
|
162
|
-
|
163
|
-
def ConfigTable.bool_config?( name )
|
164
|
-
ent = get_entry(name) or return false
|
165
|
-
ent[1] == 'yes/no'
|
166
|
-
end
|
167
|
-
|
168
|
-
def ConfigTable.value_config?( name )
|
169
|
-
ent = get_entry(name) or return false
|
170
|
-
ent[1] != 'yes/no'
|
171
|
-
end
|
172
|
-
|
173
|
-
def ConfigTable.path_config?( name )
|
174
|
-
ent = get_entry(name) or return false
|
175
|
-
ent[1] == 'path'
|
176
|
-
end
|
177
|
-
|
178
|
-
|
179
|
-
class << self
|
180
|
-
|
181
|
-
alias newobj new
|
182
|
-
|
183
|
-
def new
|
184
|
-
c = newobj()
|
185
|
-
c.__send__ :init
|
186
|
-
c
|
187
|
-
end
|
188
|
-
|
189
|
-
def load
|
190
|
-
c = newobj()
|
191
|
-
raise InstallError, "#{File.basename $0} config first"\
|
192
|
-
unless File.file? SAVE_FILE
|
193
|
-
File.foreach(SAVE_FILE) do |line|
|
194
|
-
k, v = line.split(/=/, 2)
|
195
|
-
c.instance_eval {
|
196
|
-
@table[k] = v.strip
|
197
|
-
}
|
198
|
-
end
|
199
|
-
c
|
200
|
-
end
|
201
|
-
|
202
|
-
end
|
203
|
-
|
204
|
-
def initialize
|
205
|
-
@table = {}
|
206
|
-
end
|
207
|
-
|
208
|
-
def init
|
209
|
-
DESCRIPTER.each do |k, (default, vname, desc, default2)|
|
210
|
-
@table[k] = default
|
211
|
-
end
|
212
|
-
end
|
213
|
-
private :init
|
214
|
-
|
215
|
-
def save
|
216
|
-
File.open(SAVE_FILE, 'w') {|f|
|
217
|
-
@table.each do |k, v|
|
218
|
-
f.printf "%s=%s\n", k, v if v
|
219
|
-
end
|
220
|
-
}
|
221
|
-
end
|
222
|
-
|
223
|
-
def []=( k, v )
|
224
|
-
ConfigTable.config_key? k or raise InstallError, "unknown config option #{k}"
|
225
|
-
if ConfigTable.path_config? k
|
226
|
-
@table[k] = (v[0,1] != '$') ? File.expand_path(v) : v
|
227
|
-
else
|
228
|
-
@table[k] = v
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
def []( key )
|
233
|
-
@table[key] or return nil
|
234
|
-
@table[key].gsub(%r<\$([^/]+)>) { self[$1] }
|
235
|
-
end
|
236
|
-
|
237
|
-
def set_raw( key, val )
|
238
|
-
@table[key] = val
|
239
|
-
end
|
240
|
-
|
241
|
-
def get_raw( key )
|
242
|
-
@table[key]
|
243
|
-
end
|
244
|
-
|
245
|
-
end
|
246
|
-
|
247
|
-
|
248
|
-
class MetaConfigEnvironment
|
249
|
-
|
250
|
-
def self.eval_file( file )
|
251
|
-
return unless File.file? file
|
252
|
-
new.instance_eval File.read_all(file), file, 1
|
253
|
-
end
|
254
|
-
|
255
|
-
private
|
256
|
-
|
257
|
-
def config_names
|
258
|
-
ConfigTable.keys
|
259
|
-
end
|
260
|
-
|
261
|
-
def config?( name )
|
262
|
-
ConfigTable.config_key? name
|
263
|
-
end
|
264
|
-
|
265
|
-
def bool_config?( name )
|
266
|
-
ConfigTable.bool_config? name
|
267
|
-
end
|
268
|
-
|
269
|
-
def value_config?( name )
|
270
|
-
ConfigTable.value_config? name
|
271
|
-
end
|
272
|
-
|
273
|
-
def path_config?( name )
|
274
|
-
ConfigTable.path_config? name
|
275
|
-
end
|
276
|
-
|
277
|
-
def add_config( name, argname, default, desc )
|
278
|
-
ConfigTable.add_entry name,[default,argname,desc]
|
279
|
-
end
|
280
|
-
|
281
|
-
def add_path_config( name, default, desc )
|
282
|
-
add_config name, 'path', default, desc
|
283
|
-
end
|
284
|
-
|
285
|
-
def add_bool_config( name, default, desc )
|
286
|
-
add_config name, 'yes/no', default ? 'yes' : 'no', desc
|
287
|
-
end
|
288
|
-
|
289
|
-
def set_config_default( name, default )
|
290
|
-
if bool_config? name
|
291
|
-
ConfigTable.get_entry!(name)[0] = default ? 'yes' : 'no'
|
292
|
-
else
|
293
|
-
ConfigTable.get_entry!(name)[0] = default
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
def remove_config( name )
|
298
|
-
ent = ConfigTable.get_entry(name)
|
299
|
-
ConfigTable.remove_entry name
|
300
|
-
ent
|
301
|
-
end
|
302
|
-
|
303
|
-
end
|
304
|
-
|
305
|
-
### end config.rb
|
306
|
-
### begin fileop.rb
|
307
|
-
|
308
|
-
module FileOperations
|
309
|
-
|
310
|
-
def mkdir_p( dname, prefix = nil )
|
311
|
-
dname = prefix + dname if prefix
|
312
|
-
$stderr.puts "mkdir -p #{dname}" if verbose?
|
313
|
-
return if no_harm?
|
314
|
-
|
315
|
-
# does not check '/'... it's too abnormal case
|
316
|
-
dirs = dname.split(%r<(?=/)>)
|
317
|
-
if /\A[a-z]:\z/i === dirs[0]
|
318
|
-
disk = dirs.shift
|
319
|
-
dirs[0] = disk + dirs[0]
|
320
|
-
end
|
321
|
-
dirs.each_index do |idx|
|
322
|
-
path = dirs[0..idx].join('')
|
323
|
-
Dir.mkdir path unless dir? path
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
def rm_f( fname )
|
328
|
-
$stderr.puts "rm -f #{fname}" if verbose?
|
329
|
-
return if no_harm?
|
330
|
-
|
331
|
-
if File.exist? fname or File.symlink? fname
|
332
|
-
File.chmod 0777, fname
|
333
|
-
File.unlink fname
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
def rm_rf( dn )
|
338
|
-
$stderr.puts "rm -rf #{dn}" if verbose?
|
339
|
-
return if no_harm?
|
340
|
-
|
341
|
-
Dir.chdir dn
|
342
|
-
Dir.foreach('.') do |fn|
|
343
|
-
next if fn == '.'
|
344
|
-
next if fn == '..'
|
345
|
-
if dir? fn
|
346
|
-
verbose_off {
|
347
|
-
rm_rf fn
|
348
|
-
}
|
349
|
-
else
|
350
|
-
verbose_off {
|
351
|
-
rm_f fn
|
352
|
-
}
|
353
|
-
end
|
354
|
-
end
|
355
|
-
Dir.chdir '..'
|
356
|
-
Dir.rmdir dn
|
357
|
-
end
|
358
|
-
|
359
|
-
def mv( src, dest )
|
360
|
-
rm_f dest
|
361
|
-
begin
|
362
|
-
File.link src, dest
|
363
|
-
rescue
|
364
|
-
File.write dest, File.read_all(src)
|
365
|
-
File.chmod File.stat(src).mode, dest
|
366
|
-
end
|
367
|
-
rm_f src
|
368
|
-
end
|
369
|
-
|
370
|
-
def install( from, dest, mode, prefix = nil )
|
371
|
-
$stderr.puts "install #{from} #{dest}" if verbose?
|
372
|
-
return if no_harm?
|
373
|
-
|
374
|
-
realdest = prefix + dest if prefix
|
375
|
-
if dir? realdest
|
376
|
-
realdest += '/' + File.basename(from)
|
377
|
-
end
|
378
|
-
str = File.read_all(from)
|
379
|
-
if diff? str, realdest
|
380
|
-
verbose_off {
|
381
|
-
rm_f realdest if File.exist? realdest
|
382
|
-
}
|
383
|
-
File.write realdest, str
|
384
|
-
File.chmod mode, realdest
|
385
|
-
|
386
|
-
File.open(objdir + '/InstalledFiles', 'a') {|f| f.puts realdest }
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
def diff?( orig, targ )
|
391
|
-
return true unless File.exist? targ
|
392
|
-
orig != File.read_all(targ)
|
393
|
-
end
|
394
|
-
|
395
|
-
def command( str )
|
396
|
-
$stderr.puts str if verbose?
|
397
|
-
system str or raise RuntimeError, "'system #{str}' failed"
|
398
|
-
end
|
399
|
-
|
400
|
-
def ruby( str )
|
401
|
-
command config('ruby-prog') + ' ' + str
|
402
|
-
end
|
403
|
-
|
404
|
-
def dir?( dname )
|
405
|
-
# for corrupted windows stat()
|
406
|
-
File.directory?((dname[-1,1] == '/') ? dname : dname + '/')
|
407
|
-
end
|
408
|
-
|
409
|
-
def all_files( dname )
|
410
|
-
Dir.open(dname) {|d|
|
411
|
-
return d.find_all {|n| File.file? "#{dname}/#{n}" }
|
412
|
-
}
|
413
|
-
end
|
414
|
-
|
415
|
-
def all_dirs( dname )
|
416
|
-
Dir.open(dname) {|d|
|
417
|
-
return d.find_all {|n| dir? "#{dname}/#{n}" } - %w(. ..)
|
418
|
-
}
|
419
|
-
end
|
420
|
-
|
421
|
-
end
|
422
|
-
|
423
|
-
### end fileop.rb
|
424
|
-
### begin base.rb
|
425
|
-
|
426
|
-
class InstallError < StandardError; end
|
427
|
-
|
428
|
-
|
429
|
-
class Installer
|
430
|
-
|
431
|
-
Version = '3.1.3'
|
432
|
-
Copyright = 'Copyright (c) 2000-2002 Minero Aoki'
|
433
|
-
|
434
|
-
|
435
|
-
@toplevel = nil
|
436
|
-
|
437
|
-
def self.declear_toplevel_installer( inst )
|
438
|
-
@toplevel and
|
439
|
-
raise ArgumentError, 'more than one toplevel installer decleared'
|
440
|
-
@toplevel = inst
|
441
|
-
end
|
442
|
-
|
443
|
-
def self.toplevel_installer
|
444
|
-
@toplevel
|
445
|
-
end
|
446
|
-
|
447
|
-
|
448
|
-
FILETYPES = %w( bin lib ext data )
|
449
|
-
|
450
|
-
include FileOperations
|
451
|
-
|
452
|
-
def initialize( config, opt, srcroot, objroot )
|
453
|
-
@config = config
|
454
|
-
@options = opt
|
455
|
-
@srcdir = File.expand_path(srcroot)
|
456
|
-
@objdir = File.expand_path(objroot)
|
457
|
-
@currdir = '.'
|
458
|
-
end
|
459
|
-
|
460
|
-
def inspect
|
461
|
-
"#<#{self.class} #{__id__}>"
|
462
|
-
end
|
463
|
-
|
464
|
-
#
|
465
|
-
# configs/options
|
466
|
-
#
|
467
|
-
|
468
|
-
def get_config( key )
|
469
|
-
@config[key]
|
470
|
-
end
|
471
|
-
|
472
|
-
alias config get_config
|
473
|
-
|
474
|
-
def set_config( key, val )
|
475
|
-
@config[key] = val
|
476
|
-
end
|
477
|
-
|
478
|
-
def no_harm?
|
479
|
-
@options['no-harm']
|
480
|
-
end
|
481
|
-
|
482
|
-
def verbose?
|
483
|
-
@options['verbose']
|
484
|
-
end
|
485
|
-
|
486
|
-
def verbose_off
|
487
|
-
save, @options['verbose'] = @options['verbose'], false
|
488
|
-
yield
|
489
|
-
@options['verbose'] = save
|
490
|
-
end
|
491
|
-
|
492
|
-
#
|
493
|
-
# srcdir/objdir
|
494
|
-
#
|
495
|
-
|
496
|
-
attr_reader :srcdir
|
497
|
-
alias srcdir_root srcdir
|
498
|
-
alias package_root srcdir
|
499
|
-
|
500
|
-
def curr_srcdir
|
501
|
-
"#{@srcdir}/#{@currdir}"
|
502
|
-
end
|
503
|
-
|
504
|
-
attr_reader :objdir
|
505
|
-
alias objdir_root objdir
|
506
|
-
|
507
|
-
def curr_objdir
|
508
|
-
"#{@objdir}/#{@currdir}"
|
509
|
-
end
|
510
|
-
|
511
|
-
def srcfile( path )
|
512
|
-
curr_srcdir + '/' + path
|
513
|
-
end
|
514
|
-
|
515
|
-
def srcexist?( path )
|
516
|
-
File.exist? srcfile(path)
|
517
|
-
end
|
518
|
-
|
519
|
-
def srcdirectory?( path )
|
520
|
-
dir? srcfile(path)
|
521
|
-
end
|
522
|
-
|
523
|
-
def srcfile?( path )
|
524
|
-
File.file? srcfile(path)
|
525
|
-
end
|
526
|
-
|
527
|
-
def srcentries( path = '.' )
|
528
|
-
Dir.open(curr_srcdir + '/' + path) {|d|
|
529
|
-
return d.to_a - %w(. ..) - hookfilenames
|
530
|
-
}
|
531
|
-
end
|
532
|
-
|
533
|
-
def srcfiles( path = '.' )
|
534
|
-
srcentries(path).find_all {|fname|
|
535
|
-
File.file? File.join(curr_srcdir, path, fname)
|
536
|
-
}
|
537
|
-
end
|
538
|
-
|
539
|
-
def srcdirectories( path = '.' )
|
540
|
-
srcentries(path).find_all {|fname|
|
541
|
-
dir? File.join(curr_srcdir, path, fname)
|
542
|
-
}
|
543
|
-
end
|
544
|
-
|
545
|
-
def dive_into( rel )
|
546
|
-
return unless dir? "#{@srcdir}/#{rel}"
|
547
|
-
|
548
|
-
dir = File.basename(rel)
|
549
|
-
Dir.mkdir dir unless dir? dir
|
550
|
-
save = Dir.pwd
|
551
|
-
Dir.chdir dir
|
552
|
-
$stderr.puts '---> ' + rel if verbose?
|
553
|
-
@currdir = rel
|
554
|
-
yield
|
555
|
-
Dir.chdir save
|
556
|
-
$stderr.puts '<--- ' + rel if verbose?
|
557
|
-
@currdir = File.dirname(rel)
|
558
|
-
end
|
559
|
-
|
560
|
-
#
|
561
|
-
# config
|
562
|
-
#
|
563
|
-
|
564
|
-
def exec_config
|
565
|
-
exec_task_traverse 'config'
|
566
|
-
end
|
567
|
-
|
568
|
-
def config_dir_bin( rel )
|
569
|
-
end
|
570
|
-
|
571
|
-
def config_dir_lib( rel )
|
572
|
-
end
|
573
|
-
|
574
|
-
def config_dir_ext( rel )
|
575
|
-
extconf if extdir? curr_srcdir
|
576
|
-
end
|
577
|
-
|
578
|
-
def extconf
|
579
|
-
opt = @options['config-opt'].join(' ')
|
580
|
-
command "#{config('ruby-prog')} #{curr_srcdir}/extconf.rb #{opt}"
|
581
|
-
end
|
582
|
-
|
583
|
-
def config_dir_data( rel )
|
584
|
-
end
|
585
|
-
|
586
|
-
#
|
587
|
-
# setup
|
588
|
-
#
|
589
|
-
|
590
|
-
def exec_setup
|
591
|
-
exec_task_traverse 'setup'
|
592
|
-
end
|
593
|
-
|
594
|
-
def setup_dir_bin( relpath )
|
595
|
-
all_files(curr_srcdir).each do |fname|
|
596
|
-
add_rubypath "#{curr_srcdir}/#{fname}"
|
597
|
-
end
|
598
|
-
end
|
599
|
-
|
600
|
-
SHEBANG_RE = /\A\#!\s*\S*ruby\S*/
|
601
|
-
|
602
|
-
def add_rubypath( path )
|
603
|
-
$stderr.puts %Q<set #! line to "\#!#{config('ruby-path')}" for #{path} ...> if verbose?
|
604
|
-
return if no_harm?
|
605
|
-
|
606
|
-
tmpfile = File.basename(path) + '.tmp'
|
607
|
-
begin
|
608
|
-
File.open(path) {|r|
|
609
|
-
File.open(tmpfile, 'w') {|w|
|
610
|
-
first = r.gets
|
611
|
-
return unless SHEBANG_RE === first # reject '/usr/bin/env ruby'
|
612
|
-
|
613
|
-
w.print first.sub(SHEBANG_RE, '#!' + config('ruby-path'))
|
614
|
-
w.write r.read
|
615
|
-
} }
|
616
|
-
mv tmpfile, File.basename(path)
|
617
|
-
ensure
|
618
|
-
rm_f tmpfile if File.exist? tmpfile
|
619
|
-
end
|
620
|
-
end
|
621
|
-
|
622
|
-
def setup_dir_lib( relpath )
|
623
|
-
end
|
624
|
-
|
625
|
-
def setup_dir_ext( relpath )
|
626
|
-
make if extdir?(curr_srcdir)
|
627
|
-
end
|
628
|
-
|
629
|
-
def make
|
630
|
-
command config('make-prog')
|
631
|
-
end
|
632
|
-
|
633
|
-
def setup_dir_data( relpath )
|
634
|
-
end
|
635
|
-
|
636
|
-
#
|
637
|
-
# install
|
638
|
-
#
|
639
|
-
|
640
|
-
def exec_install
|
641
|
-
exec_task_traverse 'install'
|
642
|
-
end
|
643
|
-
|
644
|
-
def install_dir_bin( rel )
|
645
|
-
install_files targfiles, config('bin-dir') + '/' + rel, 0755
|
646
|
-
end
|
647
|
-
|
648
|
-
def install_dir_lib( rel )
|
649
|
-
install_files targfiles, config('rb-dir') + '/' + rel, 0644
|
650
|
-
end
|
651
|
-
|
652
|
-
def install_dir_ext( rel )
|
653
|
-
install_dir_ext_main File.dirname(rel) if extdir?(curr_srcdir)
|
654
|
-
end
|
655
|
-
|
656
|
-
def install_dir_ext_main( rel )
|
657
|
-
install_files allext('.'), config('so-dir') + '/' + rel, 0555
|
658
|
-
end
|
659
|
-
|
660
|
-
def install_dir_data( rel )
|
661
|
-
install_files targfiles, config('data-dir') + '/' + rel, 0644
|
662
|
-
end
|
663
|
-
|
664
|
-
def install_files( list, dest, mode )
|
665
|
-
mkdir_p dest, @options['install-prefix']
|
666
|
-
list.each do |fname|
|
667
|
-
install fname, dest, mode, @options['install-prefix']
|
668
|
-
end
|
669
|
-
end
|
670
|
-
|
671
|
-
def targfiles
|
672
|
-
(targfilenames() - hookfilenames()).collect {|fname|
|
673
|
-
File.exist?(fname) ? fname : File.join(curr_srcdir(), fname)
|
674
|
-
}
|
675
|
-
end
|
676
|
-
|
677
|
-
def targfilenames
|
678
|
-
[ curr_srcdir(), '.' ].inject([]) {|ret, dir|
|
679
|
-
ret | all_files(dir)
|
680
|
-
}
|
681
|
-
end
|
682
|
-
|
683
|
-
def hookfilenames
|
684
|
-
%w( pre-%s post-%s pre-%s.rb post-%s.rb ).collect {|fmt|
|
685
|
-
%w( config setup install clean ).collect {|t| sprintf fmt, t }
|
686
|
-
}.flatten
|
687
|
-
end
|
688
|
-
|
689
|
-
def allext( dir )
|
690
|
-
_allext(dir) or raise InstallError,
|
691
|
-
"no extention exists: Have you done 'ruby #{$0} setup' ?"
|
692
|
-
end
|
693
|
-
|
694
|
-
DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/
|
695
|
-
|
696
|
-
def _allext( dir )
|
697
|
-
Dir.open(dir) {|d|
|
698
|
-
return d.find_all {|fname| DLEXT === fname }
|
699
|
-
}
|
700
|
-
end
|
701
|
-
|
702
|
-
#
|
703
|
-
# clean
|
704
|
-
#
|
705
|
-
|
706
|
-
def exec_clean
|
707
|
-
exec_task_traverse 'clean'
|
708
|
-
rm_f 'config.save'
|
709
|
-
rm_f 'InstalledFiles'
|
710
|
-
end
|
711
|
-
|
712
|
-
def clean_dir_bin( rel )
|
713
|
-
end
|
714
|
-
|
715
|
-
def clean_dir_lib( rel )
|
716
|
-
end
|
717
|
-
|
718
|
-
def clean_dir_ext( rel )
|
719
|
-
clean
|
720
|
-
end
|
721
|
-
|
722
|
-
def clean
|
723
|
-
command config('make-prog') + ' clean' if File.file? 'Makefile'
|
724
|
-
end
|
725
|
-
|
726
|
-
def clean_dir_data( rel )
|
727
|
-
end
|
728
|
-
|
729
|
-
#
|
730
|
-
# lib
|
731
|
-
#
|
732
|
-
|
733
|
-
def exec_task_traverse( task )
|
734
|
-
run_hook 'pre-' + task
|
735
|
-
FILETYPES.each do |type|
|
736
|
-
if config('without-ext') == 'yes' and type == 'ext'
|
737
|
-
$stderr.puts 'skipping ext/* by user option' if verbose?
|
738
|
-
next
|
739
|
-
end
|
740
|
-
traverse task, type, task + '_dir_' + type
|
741
|
-
end
|
742
|
-
run_hook 'post-' + task
|
743
|
-
end
|
744
|
-
|
745
|
-
def traverse( task, rel, mid )
|
746
|
-
dive_into(rel) {
|
747
|
-
run_hook 'pre-' + task
|
748
|
-
__send__ mid, rel.sub(%r_\A.*?(?:/|\z)_, '')
|
749
|
-
all_dirs(curr_srcdir).each do |d|
|
750
|
-
traverse task, rel + '/' + d, mid
|
751
|
-
end
|
752
|
-
run_hook 'post-' + task
|
753
|
-
}
|
754
|
-
end
|
755
|
-
|
756
|
-
def run_hook( name )
|
757
|
-
try_run_hook curr_srcdir + '/' + name or
|
758
|
-
try_run_hook curr_srcdir + '/' + name + '.rb'
|
759
|
-
end
|
760
|
-
|
761
|
-
def try_run_hook( fname )
|
762
|
-
return false unless File.file? fname
|
763
|
-
|
764
|
-
env = self.dup
|
765
|
-
begin
|
766
|
-
env.instance_eval File.read_all(fname), fname, 1
|
767
|
-
rescue
|
768
|
-
raise InstallError, "hook #{fname} failed:\n" + $!.message
|
769
|
-
end
|
770
|
-
true
|
771
|
-
end
|
772
|
-
|
773
|
-
def extdir?( dir )
|
774
|
-
File.exist? dir + '/MANIFEST'
|
775
|
-
end
|
776
|
-
|
777
|
-
end
|
778
|
-
|
779
|
-
### end base.rb
|
780
|
-
### begin toplevel.rb
|
781
|
-
|
782
|
-
class ToplevelInstaller < Installer
|
783
|
-
|
784
|
-
TASKS = [
|
785
|
-
[ 'config', 'saves your configurations' ],
|
786
|
-
[ 'show', 'shows current configuration' ],
|
787
|
-
[ 'setup', 'compiles extention or else' ],
|
788
|
-
[ 'install', 'installs files' ],
|
789
|
-
[ 'clean', "does `make clean' for each extention" ]
|
790
|
-
]
|
791
|
-
|
792
|
-
|
793
|
-
def initialize( root )
|
794
|
-
super nil, {'verbose' => true}, root, '.'
|
795
|
-
Installer.declear_toplevel_installer self
|
796
|
-
end
|
797
|
-
|
798
|
-
|
799
|
-
def execute
|
800
|
-
run_metaconfigs
|
801
|
-
|
802
|
-
case task = parsearg_global()
|
803
|
-
when 'config'
|
804
|
-
@config = ConfigTable.new
|
805
|
-
else
|
806
|
-
@config = ConfigTable.load
|
807
|
-
end
|
808
|
-
parsearg_TASK task
|
809
|
-
|
810
|
-
exectask task
|
811
|
-
end
|
812
|
-
|
813
|
-
|
814
|
-
def run_metaconfigs
|
815
|
-
MetaConfigEnvironment.eval_file "#{srcdir_root()}/#{metaconfig()}"
|
816
|
-
end
|
817
|
-
|
818
|
-
def metaconfig
|
819
|
-
'metaconfig'
|
820
|
-
end
|
821
|
-
|
822
|
-
|
823
|
-
def exectask( task )
|
824
|
-
if task == 'show'
|
825
|
-
exec_show
|
826
|
-
else
|
827
|
-
try task
|
828
|
-
end
|
829
|
-
end
|
830
|
-
|
831
|
-
def try( task )
|
832
|
-
$stderr.printf "#{File.basename $0}: entering %s phase...\n", task if verbose?
|
833
|
-
begin
|
834
|
-
__send__ 'exec_' + task
|
835
|
-
rescue
|
836
|
-
$stderr.printf "%s failed\n", task
|
837
|
-
raise
|
838
|
-
end
|
839
|
-
$stderr.printf "#{File.basename $0}: %s done.\n", task if verbose?
|
840
|
-
end
|
841
|
-
|
842
|
-
#
|
843
|
-
# processing arguments
|
844
|
-
#
|
845
|
-
|
846
|
-
def parsearg_global
|
847
|
-
task_re = /\A(?:#{TASKS.collect {|i| i[0] }.join '|'})\z/
|
848
|
-
|
849
|
-
while arg = ARGV.shift
|
850
|
-
case arg
|
851
|
-
when /\A\w+\z/
|
852
|
-
task_re === arg or raise InstallError, "wrong task: #{arg}"
|
853
|
-
return arg
|
854
|
-
|
855
|
-
when '-q', '--quiet'
|
856
|
-
@options['verbose'] = false
|
857
|
-
|
858
|
-
when '--verbose'
|
859
|
-
@options['verbose'] = true
|
860
|
-
|
861
|
-
when '-h', '--help'
|
862
|
-
print_usage $stdout
|
863
|
-
exit 0
|
864
|
-
|
865
|
-
when '-v', '--version'
|
866
|
-
puts "#{File.basename $0} version #{Version}"
|
867
|
-
exit 0
|
868
|
-
|
869
|
-
when '--copyright'
|
870
|
-
puts Copyright
|
871
|
-
exit 0
|
872
|
-
|
873
|
-
else
|
874
|
-
raise InstallError, "unknown global option '#{arg}'"
|
875
|
-
end
|
876
|
-
end
|
877
|
-
|
878
|
-
raise InstallError, "No task or global option given.
|
879
|
-
Typical installation procedure is:
|
880
|
-
$ ruby #{File.basename $0} config
|
881
|
-
$ ruby #{File.basename $0} setup
|
882
|
-
# ruby #{File.basename $0} install (may require root privilege)
|
883
|
-
"
|
884
|
-
end
|
885
|
-
|
886
|
-
|
887
|
-
def parsearg_TASK( task )
|
888
|
-
mid = "parsearg_#{task}"
|
889
|
-
if respond_to? mid, true
|
890
|
-
__send__ mid
|
891
|
-
else
|
892
|
-
ARGV.empty? or
|
893
|
-
raise InstallError, "#{task}: unknown options: #{ARGV.join ' '}"
|
894
|
-
end
|
895
|
-
end
|
896
|
-
|
897
|
-
def parsearg_config
|
898
|
-
re = /\A--(#{ConfigTable.keys.join '|'})(?:=(.*))?\z/
|
899
|
-
@options['config-opt'] = []
|
900
|
-
|
901
|
-
while i = ARGV.shift
|
902
|
-
if /\A--?\z/ === i
|
903
|
-
@options['config-opt'] = ARGV.dup
|
904
|
-
break
|
905
|
-
end
|
906
|
-
m = re.match(i) or raise InstallError, "config: unknown option #{i}"
|
907
|
-
name, value = m.to_a[1,2]
|
908
|
-
if value
|
909
|
-
if ConfigTable.bool_config?(name)
|
910
|
-
/\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i === value or raise InstallError, "config: --#{name} allows only yes/no for argument"
|
911
|
-
value = (/\Ay(es)?|\At(rue)/i === value) ? 'yes' : 'no'
|
912
|
-
end
|
913
|
-
else
|
914
|
-
ConfigTable.bool_config?(name) or raise InstallError, "config: --#{name} requires argument"
|
915
|
-
value = 'yes'
|
916
|
-
end
|
917
|
-
@config[name] = value
|
918
|
-
end
|
919
|
-
end
|
920
|
-
|
921
|
-
def parsearg_install
|
922
|
-
@options['no-harm'] = false
|
923
|
-
@options['install-prefix'] = ''
|
924
|
-
while a = ARGV.shift
|
925
|
-
case a
|
926
|
-
when /\A--no-harm\z/
|
927
|
-
@options['no-harm'] = true
|
928
|
-
when /\A--prefix=(.*)\z/
|
929
|
-
path = $1
|
930
|
-
path = File.expand_path(path) unless path[0,1] == '/'
|
931
|
-
@options['install-prefix'] = path
|
932
|
-
else
|
933
|
-
raise InstallError, "install: unknown option #{a}"
|
934
|
-
end
|
935
|
-
end
|
936
|
-
end
|
937
|
-
|
938
|
-
|
939
|
-
def print_usage( out )
|
940
|
-
out.puts 'Typical Installation Procedure:'
|
941
|
-
out.puts " $ ruby #{File.basename $0} config"
|
942
|
-
out.puts " $ ruby #{File.basename $0} setup"
|
943
|
-
out.puts " # ruby #{File.basename $0} install (may require root privilege)"
|
944
|
-
out.puts
|
945
|
-
out.puts 'Detailed Usage:'
|
946
|
-
out.puts " ruby #{File.basename $0} <global option>"
|
947
|
-
out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
|
948
|
-
|
949
|
-
fmt = " %-20s %s\n"
|
950
|
-
out.puts
|
951
|
-
out.puts 'Global options:'
|
952
|
-
out.printf fmt, '-q,--quiet', 'suppress message outputs'
|
953
|
-
out.printf fmt, ' --verbose', 'output messages verbosely'
|
954
|
-
out.printf fmt, '-h,--help', 'print this message'
|
955
|
-
out.printf fmt, '-v,--version', 'print version and quit'
|
956
|
-
out.printf fmt, ' --copyright', 'print copyright and quit'
|
957
|
-
|
958
|
-
out.puts
|
959
|
-
out.puts 'Tasks:'
|
960
|
-
TASKS.each do |name, desc|
|
961
|
-
out.printf " %-10s %s\n", name, desc
|
962
|
-
end
|
963
|
-
|
964
|
-
out.puts
|
965
|
-
out.puts 'Options for config:'
|
966
|
-
ConfigTable.each_definition do |name, (default, arg, desc, default2)|
|
967
|
-
out.printf " %-20s %s [%s]\n",
|
968
|
-
'--'+ name + (ConfigTable.bool_config?(name) ? '' : '='+arg),
|
969
|
-
desc,
|
970
|
-
default2 || default
|
971
|
-
end
|
972
|
-
out.printf " %-20s %s [%s]\n",
|
973
|
-
'--rbconfig=path', 'your rbconfig.rb to load', "running ruby's"
|
974
|
-
|
975
|
-
out.puts
|
976
|
-
out.puts 'Options for install:'
|
977
|
-
out.printf " %-20s %s [%s]\n",
|
978
|
-
'--no-harm', 'only display what to do if given', 'off'
|
979
|
-
out.printf " %-20s %s [%s]\n",
|
980
|
-
'--prefix', 'install path prefix', '$prefix'
|
981
|
-
|
982
|
-
out.puts
|
983
|
-
end
|
984
|
-
|
985
|
-
#
|
986
|
-
# config
|
987
|
-
#
|
988
|
-
|
989
|
-
def exec_config
|
990
|
-
super
|
991
|
-
@config.save
|
992
|
-
end
|
993
|
-
|
994
|
-
#
|
995
|
-
# show
|
996
|
-
#
|
997
|
-
|
998
|
-
def exec_show
|
999
|
-
ConfigTable.each_name do |k|
|
1000
|
-
v = @config.get_raw(k)
|
1001
|
-
if not v or v.empty?
|
1002
|
-
v = '(not specified)'
|
1003
|
-
end
|
1004
|
-
printf "%-10s %s\n", k, v
|
1005
|
-
end
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
end
|
1009
|
-
|
1010
|
-
### end toplevel.rb
|
1011
|
-
|
1012
|
-
if $0 == __FILE__
|
1013
|
-
begin
|
1014
|
-
installer = ToplevelInstaller.new(File.dirname($0))
|
1015
|
-
installer.execute
|
1016
|
-
rescue
|
1017
|
-
raise if $DEBUG
|
1018
|
-
$stderr.puts $!.message
|
1019
|
-
$stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
|
1020
|
-
exit 1
|
1021
|
-
end
|
1022
|
-
end
|