mime-types 1.15 → 1.16

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.
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{mime-types}
5
+ s.version = "1.16"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Austin Ziegler"]
9
+ s.cert_chain = ["/Users/austin/.gem/gem-public_cert.pem"]
10
+ s.date = %q{2009-03-01}
11
+ s.description = %q{MIME::Types for Ruby originally based on and synchronized with MIME::Types for Perl by Mark Overmeer, copyright 2001 - 2009. As of version 1.15, the data format for the MIME::Type list has changed and the synchronization will no longer happen.}
12
+ s.email = ["austin@rubyforge.org"]
13
+ s.extra_rdoc_files = ["History.txt", "Install.txt", "Licence.txt", "README.txt"]
14
+ s.files = ["History.txt", "Install.txt", "Licence.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/mime/types.rb", "lib/mime/types.rb.data", "setup.rb", "test/test_mime_type.rb", "test/test_mime_types.rb"]
15
+ s.has_rdoc = true
16
+ s.homepage = %q{http://mime-types.rubyforge.org/}
17
+ s.rdoc_options = ["--main", "README.txt"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{mime-types}
20
+ s.rubygems_version = %q{1.3.1}
21
+ s.signing_key = %q{/Users/austin/.gem/gem-private_key.pem}
22
+ s.summary = %q{Manages a MIME Content-Type database that will return the Content-Type for a given filename.}
23
+ s.test_files = ["test/test_mime_type.rb", "test/test_mime_types.rb"]
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 2
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ s.add_development_dependency(%q<archive-tar-minitar>, ["~> 0.5.1"])
31
+ s.add_development_dependency(%q<nokogiri>, ["~> 1.2.1"])
32
+ s.add_development_dependency(%q<hoe>, [">= 1.8.3"])
33
+ else
34
+ s.add_dependency(%q<archive-tar-minitar>, ["~> 0.5.1"])
35
+ s.add_dependency(%q<nokogiri>, ["~> 1.2.1"])
36
+ s.add_dependency(%q<hoe>, [">= 1.8.3"])
37
+ end
38
+ else
39
+ s.add_dependency(%q<archive-tar-minitar>, ["~> 0.5.1"])
40
+ s.add_dependency(%q<nokogiri>, ["~> 1.2.1"])
41
+ s.add_dependency(%q<hoe>, [">= 1.8.3"])
42
+ end
43
+ end
data/setup.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # setup.rb
3
3
  #
4
- # Copyright (c) 2000-2004 Minero Aoki
4
+ # Copyright (c) 2000-2005 Minero Aoki
5
5
  #
6
6
  # This program is free software.
7
7
  # You can distribute/modify this program under the terms of
@@ -22,178 +22,67 @@ unless File.respond_to?(:read) # Ruby 1.6
22
22
  end
23
23
  end
24
24
 
25
+ unless Errno.const_defined?(:ENOTEMPTY) # Windows?
26
+ module Errno
27
+ class ENOTEMPTY
28
+ # We do not raise this exception, implementation is not needed.
29
+ end
30
+ end
31
+ end
32
+
25
33
  def File.binread(fname)
26
34
  open(fname, 'rb') {|f|
27
35
  return f.read
28
36
  }
29
37
  end
30
38
 
31
- # for corrupted windows stat(2)
39
+ # for corrupted Windows' stat(2)
32
40
  def File.dir?(path)
33
41
  File.directory?((path[-1,1] == '/') ? path : path + '/')
34
42
  end
35
43
 
36
44
 
37
- class SetupError < StandardError; end
38
-
39
- def setup_rb_error(msg)
40
- raise SetupError, msg
41
- end
42
-
43
- #
44
- # Config
45
- #
46
-
47
- if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
48
- ARGV.delete(arg)
49
- require arg.split(/=/, 2)[1]
50
- $".push 'rbconfig.rb'
51
- else
52
- require 'rbconfig'
53
- end
54
-
55
- def multipackage_install?
56
- FileTest.directory?(File.dirname($0) + '/packages')
57
- end
58
-
59
-
60
- class ConfigItem
61
- def initialize(name, template, default, desc)
62
- @name = name.freeze
63
- @template = template
64
- @value = default
65
- @default = default.dup.freeze
66
- @description = desc
67
- end
68
-
69
- attr_reader :name
70
- attr_reader :description
71
-
72
- attr_accessor :default
73
- alias help_default default
74
-
75
- def help_opt
76
- "--#{@name}=#{@template}"
77
- end
78
-
79
- def value
80
- @value
81
- end
82
-
83
- def eval(table)
84
- @value.gsub(%r<\$([^/]+)>) { table[$1] }
85
- end
86
-
87
- def set(val)
88
- @value = check(val)
89
- end
90
-
91
- private
92
-
93
- def check(val)
94
- setup_rb_error "config: --#{name} requires argument" unless val
95
- val
96
- end
97
- end
98
-
99
- class BoolItem < ConfigItem
100
- def config_type
101
- 'bool'
102
- end
103
-
104
- def help_opt
105
- "--#{@name}"
106
- end
107
-
108
- private
45
+ class ConfigTable
109
46
 
110
- def check(val)
111
- return 'yes' unless val
112
- unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
113
- setup_rb_error "config: --#{@name} accepts only yes/no for argument"
114
- end
115
- (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
116
- end
117
- end
47
+ include Enumerable
118
48
 
119
- class PathItem < ConfigItem
120
- def config_type
121
- 'path'
49
+ def initialize(rbconfig)
50
+ @rbconfig = rbconfig
51
+ @items = []
52
+ @table = {}
53
+ # options
54
+ @install_prefix = nil
55
+ @config_opt = nil
56
+ @verbose = true
57
+ @no_harm = false
122
58
  end
123
59
 
124
- private
125
-
126
- def check(path)
127
- setup_rb_error "config: --#{@name} requires argument" unless path
128
- path[0,1] == '$' ? path : File.expand_path(path)
129
- end
130
- end
60
+ attr_accessor :install_prefix
61
+ attr_accessor :config_opt
131
62
 
132
- class ProgramItem < ConfigItem
133
- def config_type
134
- 'program'
135
- end
136
- end
63
+ attr_writer :verbose
137
64
 
138
- class SelectItem < ConfigItem
139
- def initialize(name, template, default, desc)
140
- super
141
- @ok = template.split('/')
142
- end
143
-
144
- def config_type
145
- 'select'
65
+ def verbose?
66
+ @verbose
146
67
  end
147
68
 
148
- private
69
+ attr_writer :no_harm
149
70
 
150
- def check(val)
151
- unless @ok.include?(val.strip)
152
- setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
153
- end
154
- val.strip
71
+ def no_harm?
72
+ @no_harm
155
73
  end
156
- end
157
74
 
158
- class PackageSelectionItem < ConfigItem
159
- def initialize(name, template, default, help_default, desc)
160
- super name, template, default, desc
161
- @help_default = help_default
75
+ def [](key)
76
+ lookup(key).resolve(self)
162
77
  end
163
78
 
164
- attr_reader :help_default
165
-
166
- def config_type
167
- 'package'
79
+ def []=(key, val)
80
+ lookup(key).set val
168
81
  end
169
82
 
170
- private
171
-
172
- def check(val)
173
- unless File.dir?("packages/#{val}")
174
- setup_rb_error "config: no such package: #{val}"
175
- end
176
- val
83
+ def names
84
+ @items.map {|i| i.name }
177
85
  end
178
- end
179
-
180
- class ConfigTable_class
181
-
182
- def initialize(items)
183
- @items = items
184
- @table = {}
185
- items.each do |i|
186
- @table[i.name] = i
187
- end
188
- ALIASES.each do |ali, name|
189
- @table[ali] = @table[name]
190
- end
191
- @script_extensions = ['rb']
192
- end
193
-
194
- attr_accessor :script_extensions
195
-
196
- include Enumerable
197
86
 
198
87
  def each(&block)
199
88
  @items.each(&block)
@@ -204,7 +93,7 @@ class ConfigTable_class
204
93
  end
205
94
 
206
95
  def lookup(name)
207
- @table[name] or raise ArgumentError, "no such config item: #{name}"
96
+ @table[name] or setup_rb_error "no such config item: #{name}"
208
97
  end
209
98
 
210
99
  def add(item)
@@ -219,24 +108,24 @@ class ConfigTable_class
219
108
  item
220
109
  end
221
110
 
222
- def new
223
- dup()
111
+ def load_script(path, inst = nil)
112
+ if File.file?(path)
113
+ MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
114
+ end
224
115
  end
225
116
 
226
117
  def savefile
227
118
  '.config'
228
119
  end
229
120
 
230
- def load
121
+ def load_savefile
231
122
  begin
232
- t = dup()
233
123
  File.foreach(savefile()) do |line|
234
124
  k, v = *line.split(/=/, 2)
235
- t[k] = v.strip
125
+ self[k] = v.strip
236
126
  end
237
- t
238
127
  rescue Errno::ENOENT
239
- setup_rb_error $!.message + "#{File.basename($0)} config first"
128
+ setup_rb_error $!.message + "\n#{File.basename($0)} config first"
240
129
  end
241
130
  end
242
131
 
@@ -244,117 +133,151 @@ class ConfigTable_class
244
133
  @items.each {|i| i.value }
245
134
  File.open(savefile(), 'w') {|f|
246
135
  @items.each do |i|
247
- f.printf "%s=%s\n", i.name, i.value if i.value
136
+ f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
248
137
  end
249
138
  }
250
139
  end
251
140
 
252
- def [](key)
253
- lookup(key).eval(self)
141
+ def load_standard_entries
142
+ standard_entries(@rbconfig).each do |ent|
143
+ add ent
144
+ end
254
145
  end
255
146
 
256
- def []=(key, val)
257
- lookup(key).set val
258
- end
147
+ def standard_entries(rbconfig)
148
+ c = rbconfig
149
+
150
+ rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
151
+
152
+ major = c['MAJOR'].to_i
153
+ minor = c['MINOR'].to_i
154
+ teeny = c['TEENY'].to_i
155
+ version = "#{major}.#{minor}"
156
+
157
+ # ruby ver. >= 1.4.4?
158
+ newpath_p = ((major >= 2) or
159
+ ((major == 1) and
160
+ ((minor >= 5) or
161
+ ((minor == 4) and (teeny >= 4)))))
162
+
163
+ if c['rubylibdir']
164
+ # V > 1.6.3
165
+ libruby = "#{c['prefix']}/lib/ruby"
166
+ librubyver = c['rubylibdir']
167
+ librubyverarch = c['archdir']
168
+ siteruby = c['sitedir']
169
+ siterubyver = c['sitelibdir']
170
+ siterubyverarch = c['sitearchdir']
171
+ elsif newpath_p
172
+ # 1.4.4 <= V <= 1.6.3
173
+ libruby = "#{c['prefix']}/lib/ruby"
174
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
175
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
176
+ siteruby = c['sitedir']
177
+ siterubyver = "$siteruby/#{version}"
178
+ siterubyverarch = "$siterubyver/#{c['arch']}"
179
+ else
180
+ # V < 1.4.4
181
+ libruby = "#{c['prefix']}/lib/ruby"
182
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
183
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
184
+ siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
185
+ siterubyver = siteruby
186
+ siterubyverarch = "$siterubyver/#{c['arch']}"
187
+ end
188
+ parameterize = lambda {|path|
189
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
190
+ }
259
191
 
260
- end
192
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
193
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
194
+ else
195
+ makeprog = 'make'
196
+ end
261
197
 
262
- c = ::Config::CONFIG
263
-
264
- rubypath = c['bindir'] + '/' + c['ruby_install_name']
265
-
266
- major = c['MAJOR'].to_i
267
- minor = c['MINOR'].to_i
268
- teeny = c['TEENY'].to_i
269
- version = "#{major}.#{minor}"
270
-
271
- # ruby ver. >= 1.4.4?
272
- newpath_p = ((major >= 2) or
273
- ((major == 1) and
274
- ((minor >= 5) or
275
- ((minor == 4) and (teeny >= 4)))))
276
-
277
- if c['rubylibdir']
278
- # V < 1.6.3
279
- _stdruby = c['rubylibdir']
280
- _siteruby = c['sitedir']
281
- _siterubyver = c['sitelibdir']
282
- _siterubyverarch = c['sitearchdir']
283
- elsif newpath_p
284
- # 1.4.4 <= V <= 1.6.3
285
- _stdruby = "$prefix/lib/ruby/#{version}"
286
- _siteruby = c['sitedir']
287
- _siterubyver = "$siteruby/#{version}"
288
- _siterubyverarch = "$siterubyver/#{c['arch']}"
289
- else
290
- # V < 1.4.4
291
- _stdruby = "$prefix/lib/ruby/#{version}"
292
- _siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
293
- _siterubyver = _siteruby
294
- _siterubyverarch = "$siterubyver/#{c['arch']}"
295
- end
296
- libdir = '-* dummy libdir *-'
297
- stdruby = '-* dummy rubylibdir *-'
298
- siteruby = '-* dummy site_ruby *-'
299
- siterubyver = '-* dummy site_ruby version *-'
300
- parameterize = lambda {|path|
301
- path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
302
- .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\
303
- .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\
304
- .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\
305
- .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
306
- }
307
- libdir = parameterize.call(c['libdir'])
308
- stdruby = parameterize.call(_stdruby)
309
- siteruby = parameterize.call(_siteruby)
310
- siterubyver = parameterize.call(_siterubyver)
311
- siterubyverarch = parameterize.call(_siterubyverarch)
312
-
313
- if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
314
- makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
315
- else
316
- makeprog = 'make'
317
- end
198
+ [
199
+ ExecItem.new('installdirs', 'std/site/home',
200
+ 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
201
+ {|val, table|
202
+ case val
203
+ when 'std'
204
+ table['rbdir'] = '$librubyver'
205
+ table['sodir'] = '$librubyverarch'
206
+ when 'site'
207
+ table['rbdir'] = '$siterubyver'
208
+ table['sodir'] = '$siterubyverarch'
209
+ when 'home'
210
+ setup_rb_error '$HOME was not set' unless ENV['HOME']
211
+ table['prefix'] = ENV['HOME']
212
+ table['rbdir'] = '$libdir/ruby'
213
+ table['sodir'] = '$libdir/ruby'
214
+ end
215
+ },
216
+ PathItem.new('prefix', 'path', c['prefix'],
217
+ 'path prefix of target environment'),
218
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
219
+ 'the directory for commands'),
220
+ PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
221
+ 'the directory for libraries'),
222
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
223
+ 'the directory for shared data'),
224
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
225
+ 'the directory for man pages'),
226
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
227
+ 'the directory for system configuration files'),
228
+ PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
229
+ 'the directory for local state data'),
230
+ PathItem.new('libruby', 'path', libruby,
231
+ 'the directory for ruby libraries'),
232
+ PathItem.new('librubyver', 'path', librubyver,
233
+ 'the directory for standard ruby libraries'),
234
+ PathItem.new('librubyverarch', 'path', librubyverarch,
235
+ 'the directory for standard ruby extensions'),
236
+ PathItem.new('siteruby', 'path', siteruby,
237
+ 'the directory for version-independent aux ruby libraries'),
238
+ PathItem.new('siterubyver', 'path', siterubyver,
239
+ 'the directory for aux ruby libraries'),
240
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
241
+ 'the directory for aux ruby binaries'),
242
+ PathItem.new('rbdir', 'path', '$siterubyver',
243
+ 'the directory for ruby scripts'),
244
+ PathItem.new('sodir', 'path', '$siterubyverarch',
245
+ 'the directory for ruby extentions'),
246
+ PathItem.new('rubypath', 'path', rubypath,
247
+ 'the path to set to #! line'),
248
+ ProgramItem.new('rubyprog', 'name', rubypath,
249
+ 'the ruby program using for installation'),
250
+ ProgramItem.new('makeprog', 'name', makeprog,
251
+ 'the make program to compile ruby extentions'),
252
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
253
+ 'shebang line (#!) editing mode'),
254
+ BoolItem.new('without-ext', 'yes/no', 'no',
255
+ 'does not compile/install ruby extentions')
256
+ ]
257
+ end
258
+ private :standard_entries
259
+
260
+ def load_multipackage_entries
261
+ multipackage_entries().each do |ent|
262
+ add ent
263
+ end
264
+ end
265
+
266
+ def multipackage_entries
267
+ [
268
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
269
+ 'package names that you want to install'),
270
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
271
+ 'package names that you do not want to install')
272
+ ]
273
+ end
274
+ private :multipackage_entries
318
275
 
319
- common_conf = [
320
- PathItem.new('prefix', 'path', c['prefix'],
321
- 'path prefix of target environment'),
322
- PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
323
- 'the directory for commands'),
324
- PathItem.new('libdir', 'path', libdir,
325
- 'the directory for libraries'),
326
- PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
327
- 'the directory for shared data'),
328
- PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
329
- 'the directory for man pages'),
330
- PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
331
- 'the directory for man pages'),
332
- PathItem.new('stdruby', 'path', stdruby,
333
- 'the directory for standard ruby libraries'),
334
- PathItem.new('siteruby', 'path', siteruby,
335
- 'the directory for version-independent aux ruby libraries'),
336
- PathItem.new('siterubyver', 'path', siterubyver,
337
- 'the directory for aux ruby libraries'),
338
- PathItem.new('siterubyverarch', 'path', siterubyverarch,
339
- 'the directory for aux ruby binaries'),
340
- PathItem.new('rbdir', 'path', '$siterubyver',
341
- 'the directory for ruby scripts'),
342
- PathItem.new('sodir', 'path', '$siterubyverarch',
343
- 'the directory for ruby extentions'),
344
- PathItem.new('rubypath', 'path', rubypath,
345
- 'the path to set to #! line'),
346
- ProgramItem.new('rubyprog', 'name', rubypath,
347
- 'the ruby program using for installation'),
348
- ProgramItem.new('makeprog', 'name', makeprog,
349
- 'the make program to compile ruby extentions'),
350
- SelectItem.new('shebang', 'all/ruby/never', 'ruby',
351
- 'shebang line (#!) editing mode'),
352
- BoolItem.new('without-ext', 'yes/no', 'no',
353
- 'does not compile/install ruby extentions')
354
- ]
355
- class ConfigTable_class # open again
356
276
  ALIASES = {
357
- 'std-ruby' => 'stdruby',
277
+ 'std-ruby' => 'librubyver',
278
+ 'stdruby' => 'librubyver',
279
+ 'rubylibdir' => 'librubyver',
280
+ 'archdir' => 'librubyverarch',
358
281
  'site-ruby-common' => 'siteruby', # For backward compatibility
359
282
  'site-ruby' => 'siterubyver', # For backward compatibility
360
283
  'bin-dir' => 'bindir',
@@ -368,81 +291,248 @@ class ConfigTable_class # open again
368
291
  'make-prog' => 'makeprog',
369
292
  'make' => 'makeprog'
370
293
  }
371
- end
372
- multipackage_conf = [
373
- PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
374
- 'package names that you want to install'),
375
- PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
376
- 'package names that you do not want to install')
377
- ]
378
- if multipackage_install?
379
- ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
380
- else
381
- ConfigTable = ConfigTable_class.new(common_conf)
382
- end
383
294
 
384
-
385
- module MetaConfigAPI
386
-
387
- def eval_file_ifexist(fname)
388
- instance_eval File.read(fname), fname, 1 if File.file?(fname)
295
+ def fixup
296
+ ALIASES.each do |ali, name|
297
+ @table[ali] = @table[name]
298
+ end
299
+ @items.freeze
300
+ @table.freeze
301
+ @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
389
302
  end
390
303
 
391
- def config_names
392
- ConfigTable.map {|i| i.name }
304
+ def parse_opt(opt)
305
+ m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
306
+ m.to_a[1,2]
393
307
  end
394
308
 
395
- def config?(name)
396
- ConfigTable.key?(name)
309
+ def dllext
310
+ @rbconfig['DLEXT']
397
311
  end
398
312
 
399
- def bool_config?(name)
400
- ConfigTable.lookup(name).config_type == 'bool'
313
+ def value_config?(name)
314
+ lookup(name).value?
401
315
  end
402
316
 
403
- def path_config?(name)
404
- ConfigTable.lookup(name).config_type == 'path'
405
- end
317
+ class Item
318
+ def initialize(name, template, default, desc)
319
+ @name = name.freeze
320
+ @template = template
321
+ @value = default
322
+ @default = default
323
+ @description = desc
324
+ end
406
325
 
407
- def value_config?(name)
408
- case ConfigTable.lookup(name).config_type
409
- when 'bool', 'path'
326
+ attr_reader :name
327
+ attr_reader :description
328
+
329
+ attr_accessor :default
330
+ alias help_default default
331
+
332
+ def help_opt
333
+ "--#{@name}=#{@template}"
334
+ end
335
+
336
+ def value?
410
337
  true
411
- else
412
- false
338
+ end
339
+
340
+ def value
341
+ @value
342
+ end
343
+
344
+ def resolve(table)
345
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
346
+ end
347
+
348
+ def set(val)
349
+ @value = check(val)
350
+ end
351
+
352
+ private
353
+
354
+ def check(val)
355
+ setup_rb_error "config: --#{name} requires argument" unless val
356
+ val
413
357
  end
414
358
  end
415
359
 
416
- def add_config(item)
417
- ConfigTable.add item
360
+ class BoolItem < Item
361
+ def config_type
362
+ 'bool'
363
+ end
364
+
365
+ def help_opt
366
+ "--#{@name}"
367
+ end
368
+
369
+ private
370
+
371
+ def check(val)
372
+ return 'yes' unless val
373
+ case val
374
+ when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
375
+ when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
376
+ else
377
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
378
+ end
379
+ end
418
380
  end
419
381
 
420
- def add_bool_config(name, default, desc)
421
- ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
382
+ class PathItem < Item
383
+ def config_type
384
+ 'path'
385
+ end
386
+
387
+ private
388
+
389
+ def check(path)
390
+ setup_rb_error "config: --#{@name} requires argument" unless path
391
+ path[0,1] == '$' ? path : File.expand_path(path)
392
+ end
422
393
  end
423
394
 
424
- def add_path_config(name, default, desc)
425
- ConfigTable.add PathItem.new(name, 'path', default, desc)
395
+ class ProgramItem < Item
396
+ def config_type
397
+ 'program'
398
+ end
426
399
  end
427
400
 
428
- def set_config_default(name, default)
429
- ConfigTable.lookup(name).default = default
401
+ class SelectItem < Item
402
+ def initialize(name, selection, default, desc)
403
+ super
404
+ @ok = selection.split('/')
405
+ end
406
+
407
+ def config_type
408
+ 'select'
409
+ end
410
+
411
+ private
412
+
413
+ def check(val)
414
+ unless @ok.include?(val.strip)
415
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
416
+ end
417
+ val.strip
418
+ end
430
419
  end
431
420
 
432
- def remove_config(name)
433
- ConfigTable.remove(name)
421
+ class ExecItem < Item
422
+ def initialize(name, selection, desc, &block)
423
+ super name, selection, nil, desc
424
+ @ok = selection.split('/')
425
+ @action = block
426
+ end
427
+
428
+ def config_type
429
+ 'exec'
430
+ end
431
+
432
+ def value?
433
+ false
434
+ end
435
+
436
+ def resolve(table)
437
+ setup_rb_error "$#{name()} wrongly used as option value"
438
+ end
439
+
440
+ undef set
441
+
442
+ def evaluate(val, table)
443
+ v = val.strip.downcase
444
+ unless @ok.include?(v)
445
+ setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
446
+ end
447
+ @action.call v, table
448
+ end
434
449
  end
435
450
 
436
- def add_script_extension(ext)
437
- ConfigTable.script_extensions << ext
438
- end
439
- end
451
+ class PackageSelectionItem < Item
452
+ def initialize(name, template, default, help_default, desc)
453
+ super name, template, default, desc
454
+ @help_default = help_default
455
+ end
440
456
 
457
+ attr_reader :help_default
441
458
 
442
- #
443
- # File Operations
444
- #
459
+ def config_type
460
+ 'package'
461
+ end
462
+
463
+ private
445
464
 
465
+ def check(val)
466
+ unless File.dir?("packages/#{val}")
467
+ setup_rb_error "config: no such package: #{val}"
468
+ end
469
+ val
470
+ end
471
+ end
472
+
473
+ class MetaConfigEnvironment
474
+ def initialize(config, installer)
475
+ @config = config
476
+ @installer = installer
477
+ end
478
+
479
+ def config_names
480
+ @config.names
481
+ end
482
+
483
+ def config?(name)
484
+ @config.key?(name)
485
+ end
486
+
487
+ def bool_config?(name)
488
+ @config.lookup(name).config_type == 'bool'
489
+ end
490
+
491
+ def path_config?(name)
492
+ @config.lookup(name).config_type == 'path'
493
+ end
494
+
495
+ def value_config?(name)
496
+ @config.lookup(name).config_type != 'exec'
497
+ end
498
+
499
+ def add_config(item)
500
+ @config.add item
501
+ end
502
+
503
+ def add_bool_config(name, default, desc)
504
+ @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
505
+ end
506
+
507
+ def add_path_config(name, default, desc)
508
+ @config.add PathItem.new(name, 'path', default, desc)
509
+ end
510
+
511
+ def set_config_default(name, default)
512
+ @config.lookup(name).default = default
513
+ end
514
+
515
+ def remove_config(name)
516
+ @config.remove(name)
517
+ end
518
+
519
+ # For only multipackage
520
+ def packages
521
+ raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
522
+ @installer.packages
523
+ end
524
+
525
+ # For only multipackage
526
+ def declare_packages(list)
527
+ raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
528
+ @installer.packages = list
529
+ end
530
+ end
531
+
532
+ end # class ConfigTable
533
+
534
+
535
+ # This module requires: #verbose?, #no_harm?
446
536
  module FileOperations
447
537
 
448
538
  def mkdir_p(dirname, prefix = nil)
@@ -450,7 +540,7 @@ module FileOperations
450
540
  $stderr.puts "mkdir -p #{dirname}" if verbose?
451
541
  return if no_harm?
452
542
 
453
- # does not check '/'... it's too abnormal case
543
+ # Does not check '/', it's too abnormal.
454
544
  dirs = File.expand_path(dirname).split(%r<(?=/)>)
455
545
  if /\A[a-z]:\z/i =~ dirs[0]
456
546
  disk = dirs.shift
@@ -462,49 +552,73 @@ module FileOperations
462
552
  end
463
553
  end
464
554
 
465
- def rm_f(fname)
466
- $stderr.puts "rm -f #{fname}" if verbose?
555
+ def rm_f(path)
556
+ $stderr.puts "rm -f #{path}" if verbose?
467
557
  return if no_harm?
468
-
469
- if File.exist?(fname) or File.symlink?(fname)
470
- File.chmod 0777, fname
471
- File.unlink fname
472
- end
558
+ force_remove_file path
473
559
  end
474
560
 
475
- def rm_rf(dn)
476
- $stderr.puts "rm -rf #{dn}" if verbose?
561
+ def rm_rf(path)
562
+ $stderr.puts "rm -rf #{path}" if verbose?
477
563
  return if no_harm?
564
+ remove_tree path
565
+ end
566
+
567
+ def remove_tree(path)
568
+ if File.symlink?(path)
569
+ remove_file path
570
+ elsif File.dir?(path)
571
+ remove_tree0 path
572
+ else
573
+ force_remove_file path
574
+ end
575
+ end
478
576
 
479
- Dir.chdir dn
480
- Dir.foreach('.') do |fn|
481
- next if fn == '.'
482
- next if fn == '..'
483
- if File.dir?(fn)
484
- verbose_off {
485
- rm_rf fn
486
- }
577
+ def remove_tree0(path)
578
+ Dir.foreach(path) do |ent|
579
+ next if ent == '.'
580
+ next if ent == '..'
581
+ entpath = "#{path}/#{ent}"
582
+ if File.symlink?(entpath)
583
+ remove_file entpath
584
+ elsif File.dir?(entpath)
585
+ remove_tree0 entpath
487
586
  else
488
- verbose_off {
489
- rm_f fn
490
- }
587
+ force_remove_file entpath
491
588
  end
492
589
  end
493
- Dir.chdir '..'
494
- Dir.rmdir dn
590
+ begin
591
+ Dir.rmdir path
592
+ rescue Errno::ENOTEMPTY
593
+ # directory may not be empty
594
+ end
495
595
  end
496
596
 
497
597
  def move_file(src, dest)
498
- File.unlink dest if File.exist?(dest)
598
+ force_remove_file dest
499
599
  begin
500
600
  File.rename src, dest
501
601
  rescue
502
- File.open(dest, 'wb') {|f| f.write File.binread(src) }
602
+ File.open(dest, 'wb') {|f|
603
+ f.write File.binread(src)
604
+ }
503
605
  File.chmod File.stat(src).mode, dest
504
606
  File.unlink src
505
607
  end
506
608
  end
507
609
 
610
+ def force_remove_file(path)
611
+ begin
612
+ remove_file path
613
+ rescue
614
+ end
615
+ end
616
+
617
+ def remove_file(path)
618
+ File.chmod 0777, path
619
+ File.unlink path
620
+ end
621
+
508
622
  def install(from, dest, mode, prefix = nil)
509
623
  $stderr.puts "install #{from} #{dest}" if verbose?
510
624
  return if no_harm?
@@ -536,66 +650,42 @@ module FileOperations
536
650
  new_content != File.binread(path)
537
651
  end
538
652
 
539
- def command(str)
540
- $stderr.puts str if verbose?
541
- system str or raise RuntimeError, "'system #{str}' failed"
653
+ def command(*args)
654
+ $stderr.puts args.join(' ') if verbose?
655
+ system(*args) or raise RuntimeError,
656
+ "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
542
657
  end
543
658
 
544
- def ruby(str)
545
- command config('rubyprog') + ' ' + str
659
+ def ruby(*args)
660
+ command config('rubyprog'), *args
546
661
  end
547
662
 
548
- def make(task = '')
549
- command config('makeprog') + ' ' + task
663
+ def make(task = nil)
664
+ command(*[config('makeprog'), task].compact)
550
665
  end
551
666
 
552
667
  def extdir?(dir)
553
- File.exist?(dir + '/MANIFEST')
668
+ File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
554
669
  end
555
670
 
556
- def all_files_in(dirname)
557
- Dir.open(dirname) {|d|
558
- return d.select {|ent| File.file?("#{dirname}/#{ent}") }
671
+ def files_of(dir)
672
+ Dir.open(dir) {|d|
673
+ return d.select {|ent| File.file?("#{dir}/#{ent}") }
559
674
  }
560
675
  end
561
676
 
562
- REJECT_DIRS = %w(
563
- CVS SCCS RCS CVS.adm .svn
564
- )
677
+ DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
565
678
 
566
- def all_dirs_in(dirname)
567
- Dir.open(dirname) {|d|
568
- return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
679
+ def directories_of(dir)
680
+ Dir.open(dir) {|d|
681
+ return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
569
682
  }
570
683
  end
571
684
 
572
685
  end
573
686
 
574
687
 
575
- #
576
- # Main Installer
577
- #
578
-
579
- module HookUtils
580
-
581
- def run_hook(name)
582
- try_run_hook "#{curr_srcdir()}/#{name}" or
583
- try_run_hook "#{curr_srcdir()}/#{name}.rb"
584
- end
585
-
586
- def try_run_hook(fname)
587
- return false unless File.file?(fname)
588
- begin
589
- instance_eval File.read(fname), fname, 1
590
- rescue
591
- setup_rb_error "hook #{fname} failed:\n" + $!.message
592
- end
593
- true
594
- end
595
-
596
- end
597
-
598
-
688
+ # This module requires: #srcdir_root, #objdir_root, #relpath
599
689
  module HookScriptAPI
600
690
 
601
691
  def get_config(key)
@@ -604,6 +694,7 @@ module HookScriptAPI
604
694
 
605
695
  alias config get_config
606
696
 
697
+ # obsolete: use metaconfig to change configuration
607
698
  def set_config(key, val)
608
699
  @config[key] = val
609
700
  end
@@ -612,10 +703,6 @@ module HookScriptAPI
612
703
  # srcdir/objdir (works only in the package directory)
613
704
  #
614
705
 
615
- #abstract srcdir_root
616
- #abstract objdir_root
617
- #abstract relpath
618
-
619
706
  def curr_srcdir
620
707
  "#{srcdir_root()}/#{relpath()}"
621
708
  end
@@ -637,7 +724,7 @@ module HookScriptAPI
637
724
  end
638
725
 
639
726
  def srcfile?(path)
640
- File.file? srcfile(path)
727
+ File.file?(srcfile(path))
641
728
  end
642
729
 
643
730
  def srcentries(path = '.')
@@ -663,8 +750,8 @@ end
663
750
 
664
751
  class ToplevelInstaller
665
752
 
666
- Version = '3.3.1'
667
- Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
753
+ Version = '3.4.1'
754
+ Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
668
755
 
669
756
  TASKS = [
670
757
  [ 'all', 'do config, setup, then install' ],
@@ -672,27 +759,44 @@ class ToplevelInstaller
672
759
  [ 'show', 'shows current configuration' ],
673
760
  [ 'setup', 'compiles ruby extentions and others' ],
674
761
  [ 'install', 'installs files' ],
762
+ [ 'test', 'run all tests in test/' ],
675
763
  [ 'clean', "does `make clean' for each extention" ],
676
764
  [ 'distclean',"does `make distclean' for each extention" ]
677
765
  ]
678
766
 
679
767
  def ToplevelInstaller.invoke
680
- instance().invoke
768
+ config = ConfigTable.new(load_rbconfig())
769
+ config.load_standard_entries
770
+ config.load_multipackage_entries if multipackage?
771
+ config.fixup
772
+ klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
773
+ klass.new(File.dirname($0), config).invoke
681
774
  end
682
775
 
683
- @singleton = nil
684
-
685
- def ToplevelInstaller.instance
686
- @singleton ||= new(File.dirname($0))
687
- @singleton
776
+ def ToplevelInstaller.multipackage?
777
+ File.dir?(File.dirname($0) + '/packages')
688
778
  end
689
779
 
690
- include MetaConfigAPI
780
+ def ToplevelInstaller.load_rbconfig
781
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
782
+ ARGV.delete(arg)
783
+ load File.expand_path(arg.split(/=/, 2)[1])
784
+ $".push 'rbconfig.rb'
785
+ else
786
+ require 'rbconfig'
787
+ end
788
+ ::Config::CONFIG
789
+ end
691
790
 
692
- def initialize(ardir_root)
693
- @config = nil
694
- @options = { 'verbose' => true }
791
+ def initialize(ardir_root, config)
695
792
  @ardir = File.expand_path(ardir_root)
793
+ @config = config
794
+ # cache
795
+ @valid_task_re = nil
796
+ end
797
+
798
+ def config(key)
799
+ @config[key]
696
800
  end
697
801
 
698
802
  def inspect
@@ -703,14 +807,20 @@ class ToplevelInstaller
703
807
  run_metaconfigs
704
808
  case task = parsearg_global()
705
809
  when nil, 'all'
706
- @config = load_config('config')
707
810
  parsearg_config
708
811
  init_installers
709
812
  exec_config
710
813
  exec_setup
711
814
  exec_install
712
815
  else
713
- @config = load_config(task)
816
+ case task
817
+ when 'config', 'test'
818
+ ;
819
+ when 'clean', 'distclean'
820
+ @config.load_savefile if File.exist?(@config.savefile)
821
+ else
822
+ @config.load_savefile
823
+ end
714
824
  __send__ "parsearg_#{task}"
715
825
  init_installers
716
826
  __send__ "exec_#{task}"
@@ -718,25 +828,11 @@ class ToplevelInstaller
718
828
  end
719
829
 
720
830
  def run_metaconfigs
721
- eval_file_ifexist "#{@ardir}/metaconfig"
722
- end
723
-
724
- def load_config(task)
725
- case task
726
- when 'config'
727
- ConfigTable.new
728
- when 'clean', 'distclean'
729
- if File.exist?(ConfigTable.savefile)
730
- then ConfigTable.load
731
- else ConfigTable.new
732
- end
733
- else
734
- ConfigTable.load
735
- end
831
+ @config.load_script "#{@ardir}/metaconfig"
736
832
  end
737
833
 
738
834
  def init_installers
739
- @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
835
+ @installer = Installer.new(@config, @ardir, File.expand_path('.'))
740
836
  end
741
837
 
742
838
  #
@@ -760,78 +856,89 @@ class ToplevelInstaller
760
856
  #
761
857
 
762
858
  def parsearg_global
763
- valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
764
-
765
859
  while arg = ARGV.shift
766
860
  case arg
767
861
  when /\A\w+\z/
768
- setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
862
+ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
769
863
  return arg
770
-
771
864
  when '-q', '--quiet'
772
- @options['verbose'] = false
773
-
774
- when '--verbose'
775
- @options['verbose'] = true
776
-
777
- when '-h', '--help'
865
+ @config.verbose = false
866
+ when '--verbose'
867
+ @config.verbose = true
868
+ when '--help'
778
869
  print_usage $stdout
779
870
  exit 0
780
-
781
- when '-v', '--version'
871
+ when '--version'
782
872
  puts "#{File.basename($0)} version #{Version}"
783
873
  exit 0
784
-
785
874
  when '--copyright'
786
875
  puts Copyright
787
876
  exit 0
788
-
789
877
  else
790
878
  setup_rb_error "unknown global option '#{arg}'"
791
879
  end
792
880
  end
793
-
794
881
  nil
795
882
  end
796
883
 
884
+ def valid_task?(t)
885
+ valid_task_re() =~ t
886
+ end
887
+
888
+ def valid_task_re
889
+ @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
890
+ end
797
891
 
798
892
  def parsearg_no_options
799
893
  unless ARGV.empty?
800
- setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}"
894
+ task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
895
+ setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
801
896
  end
802
897
  end
803
898
 
804
899
  alias parsearg_show parsearg_no_options
805
900
  alias parsearg_setup parsearg_no_options
901
+ alias parsearg_test parsearg_no_options
806
902
  alias parsearg_clean parsearg_no_options
807
903
  alias parsearg_distclean parsearg_no_options
808
904
 
809
905
  def parsearg_config
810
- re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
811
- @options['config-opt'] = []
812
-
906
+ evalopt = []
907
+ set = []
908
+ @config.config_opt = []
813
909
  while i = ARGV.shift
814
910
  if /\A--?\z/ =~ i
815
- @options['config-opt'] = ARGV.dup
911
+ @config.config_opt = ARGV.dup
816
912
  break
817
913
  end
818
- m = re.match(i) or setup_rb_error "config: unknown option #{i}"
819
- name, value = *m.to_a[1,2]
820
- @config[name] = value
914
+ name, value = *@config.parse_opt(i)
915
+ if @config.value_config?(name)
916
+ @config[name] = value
917
+ else
918
+ evalopt.push [name, value]
919
+ end
920
+ set.push name
921
+ end
922
+ evalopt.each do |name, value|
923
+ @config.lookup(name).evaluate value, @config
924
+ end
925
+ # Check if configuration is valid
926
+ set.each do |n|
927
+ @config[n] if @config.value_config?(n)
821
928
  end
822
929
  end
823
930
 
824
931
  def parsearg_install
825
- @options['no-harm'] = false
826
- @options['install-prefix'] = ''
932
+ @config.no_harm = false
933
+ @config.install_prefix = ''
827
934
  while a = ARGV.shift
828
935
  case a
829
- when /\A--no-harm\z/
830
- @options['no-harm'] = true
831
- when /\A--prefix=(.*)\z/
832
- path = $1
936
+ when '--no-harm'
937
+ @config.no_harm = true
938
+ when /\A--prefix=/
939
+ path = a.split(/=/, 2)[1]
833
940
  path = File.expand_path(path) unless path[0,1] == '/'
834
- @options['install-prefix'] = path
941
+ @config.install_prefix = path
835
942
  else
836
943
  setup_rb_error "install: unknown option #{a}"
837
944
  end
@@ -853,8 +960,8 @@ class ToplevelInstaller
853
960
  out.puts 'Global options:'
854
961
  out.printf fmt, '-q,--quiet', 'suppress message outputs'
855
962
  out.printf fmt, ' --verbose', 'output messages verbosely'
856
- out.printf fmt, '-h,--help', 'print this message'
857
- out.printf fmt, '-v,--version', 'print version and quit'
963
+ out.printf fmt, ' --help', 'print this message'
964
+ out.printf fmt, ' --version', 'print version and quit'
858
965
  out.printf fmt, ' --copyright', 'print copyright and quit'
859
966
  out.puts
860
967
  out.puts 'Tasks:'
@@ -865,14 +972,14 @@ class ToplevelInstaller
865
972
  fmt = " %-24s %s [%s]\n"
866
973
  out.puts
867
974
  out.puts 'Options for CONFIG or ALL:'
868
- ConfigTable.each do |item|
975
+ @config.each do |item|
869
976
  out.printf fmt, item.help_opt, item.description, item.help_default
870
977
  end
871
978
  out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
872
979
  out.puts
873
980
  out.puts 'Options for INSTALL:'
874
981
  out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
875
- out.printf fmt, '--prefix=path', 'install path prefix', '$prefix'
982
+ out.printf fmt, '--prefix=path', 'install path prefix', ''
876
983
  out.puts
877
984
  end
878
985
 
@@ -893,9 +1000,13 @@ class ToplevelInstaller
893
1000
  @installer.exec_install
894
1001
  end
895
1002
 
1003
+ def exec_test
1004
+ @installer.exec_test
1005
+ end
1006
+
896
1007
  def exec_show
897
- ConfigTable.each do |i|
898
- printf "%-20s %s\n", i.name, i.value
1008
+ @config.each do |i|
1009
+ printf "%-20s %s\n", i.name, i.value if i.value?
899
1010
  end
900
1011
  end
901
1012
 
@@ -907,36 +1018,45 @@ class ToplevelInstaller
907
1018
  @installer.exec_distclean
908
1019
  end
909
1020
 
910
- end
1021
+ end # class ToplevelInstaller
911
1022
 
912
1023
 
913
1024
  class ToplevelInstallerMulti < ToplevelInstaller
914
1025
 
915
- include HookUtils
916
- include HookScriptAPI
917
1026
  include FileOperations
918
1027
 
919
- def initialize(ardir)
1028
+ def initialize(ardir_root, config)
920
1029
  super
921
- @packages = all_dirs_in("#{@ardir}/packages")
1030
+ @packages = directories_of("#{@ardir}/packages")
922
1031
  raise 'no package exists' if @packages.empty?
1032
+ @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
923
1033
  end
924
1034
 
925
1035
  def run_metaconfigs
926
- eval_file_ifexist "#{@ardir}/metaconfig"
1036
+ @config.load_script "#{@ardir}/metaconfig", self
927
1037
  @packages.each do |name|
928
- eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
1038
+ @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
929
1039
  end
930
1040
  end
931
1041
 
1042
+ attr_reader :packages
1043
+
1044
+ def packages=(list)
1045
+ raise 'package list is empty' if list.empty?
1046
+ list.each do |name|
1047
+ raise "directory packages/#{name} does not exist"\
1048
+ unless File.dir?("#{@ardir}/packages/#{name}")
1049
+ end
1050
+ @packages = list
1051
+ end
1052
+
932
1053
  def init_installers
933
1054
  @installers = {}
934
1055
  @packages.each do |pack|
935
- @installers[pack] = Installer.new(@config, @options,
1056
+ @installers[pack] = Installer.new(@config,
936
1057
  "#{@ardir}/packages/#{pack}",
937
1058
  "packages/#{pack}")
938
1059
  end
939
-
940
1060
  with = extract_selection(config('with'))
941
1061
  without = extract_selection(config('without'))
942
1062
  @selected = @installers.keys.select {|name|
@@ -960,21 +1080,6 @@ class ToplevelInstallerMulti < ToplevelInstaller
960
1080
  f.puts
961
1081
  end
962
1082
 
963
- #
964
- # multi-package metaconfig API
965
- #
966
-
967
- attr_reader :packages
968
-
969
- def declare_packages(list)
970
- raise 'package list is empty' if list.empty?
971
- list.each do |name|
972
- raise "directory packages/#{name} does not exist"\
973
- unless File.dir?("#{@ardir}/packages/#{name}")
974
- end
975
- @packages = list
976
- end
977
-
978
1083
  #
979
1084
  # Task Handlers
980
1085
  #
@@ -998,15 +1103,21 @@ class ToplevelInstallerMulti < ToplevelInstaller
998
1103
  run_hook 'post-install'
999
1104
  end
1000
1105
 
1106
+ def exec_test
1107
+ run_hook 'pre-test'
1108
+ each_selected_installers {|inst| inst.exec_test }
1109
+ run_hook 'post-test'
1110
+ end
1111
+
1001
1112
  def exec_clean
1002
- rm_f ConfigTable.savefile
1113
+ rm_f @config.savefile
1003
1114
  run_hook 'pre-clean'
1004
1115
  each_selected_installers {|inst| inst.exec_clean }
1005
1116
  run_hook 'post-clean'
1006
1117
  end
1007
1118
 
1008
1119
  def exec_distclean
1009
- rm_f ConfigTable.savefile
1120
+ rm_f @config.savefile
1010
1121
  run_hook 'pre-distclean'
1011
1122
  each_selected_installers {|inst| inst.exec_distclean }
1012
1123
  run_hook 'post-distclean'
@@ -1019,7 +1130,7 @@ class ToplevelInstallerMulti < ToplevelInstaller
1019
1130
  def each_selected_installers
1020
1131
  Dir.mkdir 'packages' unless File.dir?('packages')
1021
1132
  @selected.each do |pack|
1022
- $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1133
+ $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1023
1134
  Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1024
1135
  Dir.chdir "packages/#{pack}"
1025
1136
  yield @installers[pack]
@@ -1027,28 +1138,32 @@ class ToplevelInstallerMulti < ToplevelInstaller
1027
1138
  end
1028
1139
  end
1029
1140
 
1141
+ def run_hook(id)
1142
+ @root_installer.run_hook id
1143
+ end
1144
+
1145
+ # module FileOperations requires this
1030
1146
  def verbose?
1031
- @options['verbose']
1147
+ @config.verbose?
1032
1148
  end
1033
1149
 
1150
+ # module FileOperations requires this
1034
1151
  def no_harm?
1035
- @options['no-harm']
1152
+ @config.no_harm?
1036
1153
  end
1037
1154
 
1038
- end
1155
+ end # class ToplevelInstallerMulti
1039
1156
 
1040
1157
 
1041
1158
  class Installer
1042
1159
 
1043
- FILETYPES = %w( bin lib ext data )
1160
+ FILETYPES = %w( bin lib ext data conf man )
1044
1161
 
1045
- include HookScriptAPI
1046
- include HookUtils
1047
1162
  include FileOperations
1163
+ include HookScriptAPI
1048
1164
 
1049
- def initialize(config, opt, srcroot, objroot)
1165
+ def initialize(config, srcroot, objroot)
1050
1166
  @config = config
1051
- @options = opt
1052
1167
  @srcdir = File.expand_path(srcroot)
1053
1168
  @objdir = File.expand_path(objroot)
1054
1169
  @currdir = '.'
@@ -1058,6 +1173,9 @@ class Installer
1058
1173
  "#<#{self.class} #{File.basename(@srcdir)}>"
1059
1174
  end
1060
1175
 
1176
+ def noop(rel)
1177
+ end
1178
+
1061
1179
  #
1062
1180
  # Hook Script API base methods
1063
1181
  #
@@ -1075,23 +1193,25 @@ class Installer
1075
1193
  end
1076
1194
 
1077
1195
  #
1078
- # configs/options
1196
+ # Config Access
1079
1197
  #
1080
1198
 
1081
- def no_harm?
1082
- @options['no-harm']
1199
+ # module FileOperations requires this
1200
+ def verbose?
1201
+ @config.verbose?
1083
1202
  end
1084
1203
 
1085
- def verbose?
1086
- @options['verbose']
1204
+ # module FileOperations requires this
1205
+ def no_harm?
1206
+ @config.no_harm?
1087
1207
  end
1088
1208
 
1089
1209
  def verbose_off
1090
1210
  begin
1091
- save, @options['verbose'] = @options['verbose'], false
1211
+ save, @config.verbose = @config.verbose?, false
1092
1212
  yield
1093
1213
  ensure
1094
- @options['verbose'] = save
1214
+ @config.verbose = save
1095
1215
  end
1096
1216
  end
1097
1217
 
@@ -1103,22 +1223,19 @@ class Installer
1103
1223
  exec_task_traverse 'config'
1104
1224
  end
1105
1225
 
1106
- def config_dir_bin(rel)
1107
- end
1108
-
1109
- def config_dir_lib(rel)
1110
- end
1226
+ alias config_dir_bin noop
1227
+ alias config_dir_lib noop
1111
1228
 
1112
1229
  def config_dir_ext(rel)
1113
1230
  extconf if extdir?(curr_srcdir())
1114
1231
  end
1115
1232
 
1116
- def extconf
1117
- opt = @options['config-opt'].join(' ')
1118
- command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
1119
- end
1233
+ alias config_dir_data noop
1234
+ alias config_dir_conf noop
1235
+ alias config_dir_man noop
1120
1236
 
1121
- def config_dir_data(rel)
1237
+ def extconf
1238
+ ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1122
1239
  end
1123
1240
 
1124
1241
  #
@@ -1130,39 +1247,90 @@ class Installer
1130
1247
  end
1131
1248
 
1132
1249
  def setup_dir_bin(rel)
1133
- all_files_in(curr_srcdir()).each do |fname|
1134
- adjust_shebang "#{curr_srcdir()}/#{fname}"
1250
+ files_of(curr_srcdir()).each do |fname|
1251
+ update_shebang_line "#{curr_srcdir()}/#{fname}"
1135
1252
  end
1136
1253
  end
1137
1254
 
1138
- def adjust_shebang(path)
1255
+ alias setup_dir_lib noop
1256
+
1257
+ def setup_dir_ext(rel)
1258
+ make if extdir?(curr_srcdir())
1259
+ end
1260
+
1261
+ alias setup_dir_data noop
1262
+ alias setup_dir_conf noop
1263
+ alias setup_dir_man noop
1264
+
1265
+ def update_shebang_line(path)
1139
1266
  return if no_harm?
1267
+ return if config('shebang') == 'never'
1268
+ old = Shebang.load(path)
1269
+ if old
1270
+ $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1
1271
+ new = new_shebang(old)
1272
+ return if new.to_s == old.to_s
1273
+ else
1274
+ return unless config('shebang') == 'all'
1275
+ new = Shebang.new(config('rubypath'))
1276
+ end
1277
+ $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
1278
+ open_atomic_writer(path) {|output|
1279
+ File.open(path, 'rb') {|f|
1280
+ f.gets if old # discard
1281
+ output.puts new.to_s
1282
+ output.print f.read
1283
+ }
1284
+ }
1285
+ end
1286
+
1287
+ def new_shebang(old)
1288
+ if /\Aruby/ =~ File.basename(old.cmd)
1289
+ Shebang.new(config('rubypath'), old.args)
1290
+ elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
1291
+ Shebang.new(config('rubypath'), old.args[1..-1])
1292
+ else
1293
+ return old unless config('shebang') == 'all'
1294
+ Shebang.new(config('rubypath'))
1295
+ end
1296
+ end
1297
+
1298
+ def open_atomic_writer(path, &block)
1140
1299
  tmpfile = File.basename(path) + '.tmp'
1141
1300
  begin
1142
- File.open(path, 'rb') {|r|
1143
- first = r.gets
1144
- return unless File.basename(config('rubypath')) == 'ruby'
1145
- return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
1146
- $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1147
- File.open(tmpfile, 'wb') {|w|
1148
- w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1149
- w.write r.read
1150
- }
1151
- move_file tmpfile, File.basename(path)
1152
- }
1301
+ File.open(tmpfile, 'wb', &block)
1302
+ File.rename tmpfile, File.basename(path)
1153
1303
  ensure
1154
1304
  File.unlink tmpfile if File.exist?(tmpfile)
1155
1305
  end
1156
1306
  end
1157
1307
 
1158
- def setup_dir_lib(rel)
1159
- end
1308
+ class Shebang
1309
+ def Shebang.load(path)
1310
+ line = nil
1311
+ File.open(path) {|f|
1312
+ line = f.gets
1313
+ }
1314
+ return nil unless /\A#!/ =~ line
1315
+ parse(line)
1316
+ end
1160
1317
 
1161
- def setup_dir_ext(rel)
1162
- make if extdir?(curr_srcdir())
1163
- end
1318
+ def Shebang.parse(line)
1319
+ cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
1320
+ new(cmd, args)
1321
+ end
1322
+
1323
+ def initialize(cmd, args = [])
1324
+ @cmd = cmd
1325
+ @args = args
1326
+ end
1164
1327
 
1165
- def setup_dir_data(rel)
1328
+ attr_reader :cmd
1329
+ attr_reader :args
1330
+
1331
+ def to_s
1332
+ "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
1333
+ end
1166
1334
  end
1167
1335
 
1168
1336
  #
@@ -1175,63 +1343,77 @@ class Installer
1175
1343
  end
1176
1344
 
1177
1345
  def install_dir_bin(rel)
1178
- install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
1346
+ install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1179
1347
  end
1180
1348
 
1181
1349
  def install_dir_lib(rel)
1182
- install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
1350
+ install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
1183
1351
  end
1184
1352
 
1185
1353
  def install_dir_ext(rel)
1186
1354
  return unless extdir?(curr_srcdir())
1187
- install_files ruby_extentions('.'),
1355
+ install_files rubyextentions('.'),
1188
1356
  "#{config('sodir')}/#{File.dirname(rel)}",
1189
1357
  0555
1190
1358
  end
1191
1359
 
1192
1360
  def install_dir_data(rel)
1193
- install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
1361
+ install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
1362
+ end
1363
+
1364
+ def install_dir_conf(rel)
1365
+ # FIXME: should not remove current config files
1366
+ # (rename previous file to .old/.org)
1367
+ install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
1368
+ end
1369
+
1370
+ def install_dir_man(rel)
1371
+ install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
1194
1372
  end
1195
1373
 
1196
1374
  def install_files(list, dest, mode)
1197
- mkdir_p dest, @options['install-prefix']
1375
+ mkdir_p dest, @config.install_prefix
1198
1376
  list.each do |fname|
1199
- install fname, dest, mode, @options['install-prefix']
1377
+ install fname, dest, mode, @config.install_prefix
1200
1378
  end
1201
1379
  end
1202
1380
 
1203
- def ruby_scripts
1204
- collect_filenames_auto().select {|n| /\.(#{ConfigTable.script_extensions.join('|')})\z/ =~ n }
1381
+ def libfiles
1382
+ glob_reject(%w(*.y *.output), targetfiles())
1205
1383
  end
1206
-
1384
+
1385
+ def rubyextentions(dir)
1386
+ ents = glob_select("*.#{@config.dllext}", targetfiles())
1387
+ if ents.empty?
1388
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1389
+ end
1390
+ ents
1391
+ end
1392
+
1393
+ def targetfiles
1394
+ mapdir(existfiles() - hookfiles())
1395
+ end
1396
+
1397
+ def mapdir(ents)
1398
+ ents.map {|ent|
1399
+ if File.exist?(ent)
1400
+ then ent # objdir
1401
+ else "#{curr_srcdir()}/#{ent}" # srcdir
1402
+ end
1403
+ }
1404
+ end
1405
+
1207
1406
  # picked up many entries from cvs-1.11.1/src/ignore.c
1208
- reject_patterns = %w(
1407
+ JUNK_FILES = %w(
1209
1408
  core RCSLOG tags TAGS .make.state
1210
1409
  .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1211
1410
  *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1212
1411
 
1213
1412
  *.org *.in .*
1214
1413
  )
1215
- mapping = {
1216
- '.' => '\.',
1217
- '$' => '\$',
1218
- '#' => '\#',
1219
- '*' => '.*'
1220
- }
1221
- REJECT_PATTERNS = Regexp.new('\A(?:' +
1222
- reject_patterns.map {|pat|
1223
- pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1224
- }.join('|') +
1225
- ')\z')
1226
-
1227
- def collect_filenames_auto
1228
- mapdir((existfiles() - hookfiles()).reject {|fname|
1229
- REJECT_PATTERNS =~ fname
1230
- })
1231
- end
1232
1414
 
1233
1415
  def existfiles
1234
- all_files_in(curr_srcdir()) | all_files_in('.')
1416
+ glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1235
1417
  end
1236
1418
 
1237
1419
  def hookfiles
@@ -1240,24 +1422,49 @@ class Installer
1240
1422
  }.flatten
1241
1423
  end
1242
1424
 
1243
- def mapdir(filelist)
1244
- filelist.map {|fname|
1245
- if File.exist?(fname) # objdir
1246
- fname
1247
- else # srcdir
1248
- File.join(curr_srcdir(), fname)
1249
- end
1250
- }
1425
+ def glob_select(pat, ents)
1426
+ re = globs2re([pat])
1427
+ ents.select {|ent| re =~ ent }
1251
1428
  end
1252
1429
 
1253
- def ruby_extentions(dir)
1254
- Dir.open(dir) {|d|
1255
- ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
1256
- if ents.empty?
1257
- setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1258
- end
1259
- return ents
1260
- }
1430
+ def glob_reject(pats, ents)
1431
+ re = globs2re(pats)
1432
+ ents.reject {|ent| re =~ ent }
1433
+ end
1434
+
1435
+ GLOB2REGEX = {
1436
+ '.' => '\.',
1437
+ '$' => '\$',
1438
+ '#' => '\#',
1439
+ '*' => '.*'
1440
+ }
1441
+
1442
+ def globs2re(pats)
1443
+ /\A(?:#{
1444
+ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
1445
+ })\z/
1446
+ end
1447
+
1448
+ #
1449
+ # TASK test
1450
+ #
1451
+
1452
+ TESTDIR = 'test'
1453
+
1454
+ def exec_test
1455
+ unless File.directory?('test')
1456
+ $stderr.puts 'no test in this package' if verbose?
1457
+ return
1458
+ end
1459
+ $stderr.puts 'Running tests...' if verbose?
1460
+ begin
1461
+ require 'test/unit'
1462
+ rescue LoadError
1463
+ setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
1464
+ end
1465
+ runner = Test::Unit::AutoRunner.new(true)
1466
+ runner.to_run << TESTDIR
1467
+ runner.run
1261
1468
  end
1262
1469
 
1263
1470
  #
@@ -1266,53 +1473,51 @@ class Installer
1266
1473
 
1267
1474
  def exec_clean
1268
1475
  exec_task_traverse 'clean'
1269
- rm_f ConfigTable.savefile
1476
+ rm_f @config.savefile
1270
1477
  rm_f 'InstalledFiles'
1271
1478
  end
1272
1479
 
1273
- def clean_dir_bin(rel)
1274
- end
1275
-
1276
- def clean_dir_lib(rel)
1277
- end
1480
+ alias clean_dir_bin noop
1481
+ alias clean_dir_lib noop
1482
+ alias clean_dir_data noop
1483
+ alias clean_dir_conf noop
1484
+ alias clean_dir_man noop
1278
1485
 
1279
1486
  def clean_dir_ext(rel)
1280
1487
  return unless extdir?(curr_srcdir())
1281
1488
  make 'clean' if File.file?('Makefile')
1282
1489
  end
1283
1490
 
1284
- def clean_dir_data(rel)
1285
- end
1286
-
1287
1491
  #
1288
1492
  # TASK distclean
1289
1493
  #
1290
1494
 
1291
1495
  def exec_distclean
1292
1496
  exec_task_traverse 'distclean'
1293
- rm_f ConfigTable.savefile
1497
+ rm_f @config.savefile
1294
1498
  rm_f 'InstalledFiles'
1295
1499
  end
1296
1500
 
1297
- def distclean_dir_bin(rel)
1298
- end
1299
-
1300
- def distclean_dir_lib(rel)
1301
- end
1501
+ alias distclean_dir_bin noop
1502
+ alias distclean_dir_lib noop
1302
1503
 
1303
1504
  def distclean_dir_ext(rel)
1304
1505
  return unless extdir?(curr_srcdir())
1305
1506
  make 'distclean' if File.file?('Makefile')
1306
1507
  end
1307
1508
 
1509
+ alias distclean_dir_data noop
1510
+ alias distclean_dir_conf noop
1511
+ alias distclean_dir_man noop
1512
+
1308
1513
  #
1309
- # lib
1514
+ # Traversing
1310
1515
  #
1311
1516
 
1312
1517
  def exec_task_traverse(task)
1313
1518
  run_hook "pre-#{task}"
1314
1519
  FILETYPES.each do |type|
1315
- if config('without-ext') == 'yes' and type == 'ext'
1520
+ if type == 'ext' and config('without-ext') == 'yes'
1316
1521
  $stderr.puts 'skipping ext/* by user option' if verbose?
1317
1522
  next
1318
1523
  end
@@ -1325,7 +1530,7 @@ class Installer
1325
1530
  dive_into(rel) {
1326
1531
  run_hook "pre-#{task}"
1327
1532
  __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1328
- all_dirs_in(curr_srcdir()).each do |d|
1533
+ directories_of(curr_srcdir()).each do |d|
1329
1534
  traverse task, "#{rel}/#{d}", mid
1330
1535
  end
1331
1536
  run_hook "post-#{task}"
@@ -1347,16 +1552,30 @@ class Installer
1347
1552
  @currdir = File.dirname(rel)
1348
1553
  end
1349
1554
 
1350
- end
1555
+ def run_hook(id)
1556
+ path = [ "#{curr_srcdir()}/#{id}",
1557
+ "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
1558
+ return unless path
1559
+ begin
1560
+ instance_eval File.read(path), path, 1
1561
+ rescue
1562
+ raise if $DEBUG
1563
+ setup_rb_error "hook #{path} failed:\n" + $!.message
1564
+ end
1565
+ end
1566
+
1567
+ end # class Installer
1568
+
1569
+
1570
+ class SetupError < StandardError; end
1351
1571
 
1572
+ def setup_rb_error(msg)
1573
+ raise SetupError, msg
1574
+ end
1352
1575
 
1353
1576
  if $0 == __FILE__
1354
1577
  begin
1355
- if multipackage_install?
1356
- ToplevelInstallerMulti.invoke
1357
- else
1358
- ToplevelInstaller.invoke
1359
- end
1578
+ ToplevelInstaller.invoke
1360
1579
  rescue SetupError
1361
1580
  raise if $DEBUG
1362
1581
  $stderr.puts $!.message