mime-types 1.15 → 1.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -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