rubygems-update 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (53) hide show
  1. data/ChangeLog +60 -0
  2. data/lib/rubygems.rb +18 -15
  3. data/lib/rubygems/builder.rb +29 -23
  4. data/lib/rubygems/{cmd_manager.rb → command_manager.rb} +35 -24
  5. data/lib/rubygems/commands/build_command.rb +57 -0
  6. data/lib/rubygems/commands/cert_command.rb +83 -0
  7. data/lib/rubygems/commands/check_command.rb +74 -0
  8. data/lib/rubygems/commands/cleanup_command.rb +75 -0
  9. data/lib/rubygems/commands/contents_command.rb +66 -0
  10. data/lib/rubygems/commands/dependency_command.rb +105 -0
  11. data/lib/rubygems/commands/environment_command.rb +59 -0
  12. data/lib/rubygems/commands/help_command.rb +82 -0
  13. data/lib/rubygems/commands/install_command.rb +139 -0
  14. data/lib/rubygems/commands/list_command.rb +33 -0
  15. data/lib/rubygems/commands/outdated_command.rb +21 -0
  16. data/lib/rubygems/commands/pristine_command.rb +103 -0
  17. data/lib/rubygems/commands/query_command.rb +86 -0
  18. data/lib/rubygems/commands/rdoc_command.rb +75 -0
  19. data/lib/rubygems/commands/search_command.rb +35 -0
  20. data/lib/rubygems/commands/sources_command.rb +73 -0
  21. data/lib/rubygems/commands/specification_command.rb +58 -0
  22. data/lib/rubygems/commands/uninstall_command.rb +51 -0
  23. data/lib/rubygems/commands/unpack_command.rb +76 -0
  24. data/lib/rubygems/commands/update_command.rb +102 -0
  25. data/lib/rubygems/digest/digest_adapter.rb +40 -0
  26. data/lib/rubygems/digest/md5.rb +20 -0
  27. data/lib/rubygems/digest/sha1.rb +17 -0
  28. data/lib/rubygems/digest/sha2.rb +17 -0
  29. data/lib/rubygems/format.rb +1 -1
  30. data/lib/rubygems/gem_commands.rb +6 -1407
  31. data/lib/rubygems/gem_runner.rb +2 -2
  32. data/lib/rubygems/installer.rb +13 -5
  33. data/lib/rubygems/open-uri.rb +2 -2
  34. data/lib/rubygems/package.rb +13 -14
  35. data/lib/rubygems/rubygems_version.rb +1 -1
  36. data/lib/rubygems/source_index.rb +4 -4
  37. data/lib/rubygems/specification.rb +5 -0
  38. data/lib/rubygems/validator.rb +8 -8
  39. data/setup.rb +806 -588
  40. data/test/gemutilities.rb +2 -2
  41. data/test/test_builder.rb +15 -0
  42. data/test/test_check_command.rb +1 -1
  43. data/test/test_command.rb +1 -1
  44. data/test/test_gem_digest.rb +44 -0
  45. data/test/test_gem_outdated_command.rb +2 -1
  46. data/test/test_gem_sources_command.rb +11 -6
  47. data/test/test_installer.rb +1 -1
  48. data/test/test_open_uri.rb +14 -0
  49. data/test/test_parse_commands.rb +25 -25
  50. data/test/test_process_commands.rb +5 -5
  51. data/test/test_specific_extras.rb +1 -1
  52. data/test/test_validator.rb +3 -3
  53. metadata +30 -4
@@ -15,7 +15,7 @@ module Gem
15
15
  class GemRunner
16
16
 
17
17
  def initialize(options={})
18
- @cmd_manager_class = options[:command_manager] || Gem::CommandManager
18
+ @command_manager_class = options[:command_manager] || Gem::CommandManager
19
19
  @config_file_class = options[:config_file] || Gem::ConfigFile
20
20
  @doc_manager_class = options[:doc_manager] || Gem::DocManager
21
21
  end
@@ -23,7 +23,7 @@ module Gem
23
23
  # Run the gem command with the following arguments.
24
24
  def run(args)
25
25
  do_configuration(args)
26
- cmd = @cmd_manager_class.instance
26
+ cmd = @command_manager_class.instance
27
27
  cmd.command_names.each do |c|
28
28
  Command.add_specific_extra_args c, Array(Gem.configuration[c])
29
29
  end
@@ -84,7 +84,7 @@ module Gem
84
84
  end
85
85
  end
86
86
 
87
- raise Gem::FilePermissionError.new(install_dir) unless File.writable?(install_dir)
87
+ raise Gem::FilePermissionError.new(Pathname.new(install_dir).expand_path) unless File.writable?(install_dir)
88
88
 
89
89
  # Build spec dir.
90
90
  @directory = File.join(install_dir, "gems", format.spec.full_name).untaint
@@ -347,10 +347,9 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
347
347
  # file:: [IO] The IO that contains the file data
348
348
  #
349
349
  def extract_files(directory, format)
350
- unless File.expand_path(directory) == directory then
351
- raise ArgumentError, "install directory %p not absolute" % directory
352
- end
353
-
350
+ directory = expand_and_validate(directory)
351
+ raise ArgumentError, "format required to extract from" if format.nil?
352
+
354
353
  format.file_entries.each do |entry, file_data|
355
354
  path = entry['path'].untaint
356
355
  if path =~ /\A\// then # for extra sanity
@@ -369,6 +368,15 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
369
368
  end
370
369
  end
371
370
  end
371
+
372
+ private
373
+ def expand_and_validate(directory)
374
+ directory = Pathname.new(directory).expand_path
375
+ unless directory.absolute?
376
+ raise ArgumentError, "install directory %p not absolute" % directory
377
+ end
378
+ directory.to_str
379
+ end
372
380
  end # class Installer
373
381
 
374
382
  ##
@@ -4,7 +4,7 @@ require 'time'
4
4
 
5
5
  module Kernel
6
6
  private
7
- alias open_uri_original_open open # :nodoc:
7
+ alias rubygems_open_uri_original_open open # :nodoc:
8
8
 
9
9
  # makes possible to open various resources including URIs.
10
10
  # If the first argument respond to `open' method,
@@ -29,7 +29,7 @@ module Kernel
29
29
  (uri = URI.parse(name)).respond_to?(:open)
30
30
  uri.open(*rest, &block)
31
31
  else
32
- open_uri_original_open(name, *rest, &block)
32
+ rubygems_open_uri_original_open(name, *rest, &block)
33
33
  end
34
34
  end
35
35
  module_function :open
@@ -607,21 +607,20 @@ module Gem::Package
607
607
 
608
608
  # Return an IO stream for the zipped entry.
609
609
  #
610
- # If zlib is earlier than 1.2.1, then read the entry into memory
611
- # and create a string IO object from it. This avoids a "buffer
612
- # error" problem on windows when using an earlier version of zlib.
613
- # This problem has not been observed in versions of zlib 1.2.1 or
614
- # later. (Update: Kornelius Kalnbach has reported seeing it in
615
- # zlib 1.2.1, so the condition now provides the workaround for
616
- # 1.2.1 as well)
610
+ # NOTE: Originally this method used two approaches, Return a GZipReader
611
+ # directly, or read the GZipReader into a string and return a StringIO on
612
+ # the string. The string IO approach was used for versions of ZLib before
613
+ # 1.2.1 to avoid buffer errors on windows machines. Then we found that
614
+ # errors happened with 1.2.1 as well, so we changed the condition. Then
615
+ # we discovered errors occurred with versions as late as 1.2.3. At this
616
+ # point (after some benchmarking to show we weren't seriously crippling
617
+ # the unpacking speed) we threw our hands in the air and declared that
618
+ # this method would use the String IO approach on all platforms at all
619
+ # times. And that's the way it is.
617
620
  def zipped_stream(entry)
618
- if Zlib::ZLIB_VERSION <= '1.2.1'
619
- zis = Zlib::GzipReader.new entry
620
- dis = zis.read
621
- is = StringIO.new(dis)
622
- else
623
- is = Zlib::GzipReader.new entry
624
- end
621
+ zis = Zlib::GzipReader.new entry
622
+ dis = zis.read
623
+ is = StringIO.new(dis)
625
624
  ensure
626
625
  zis.finish if zis
627
626
  end
@@ -2,5 +2,5 @@
2
2
  # This file is auto-generated by build scripts.
3
3
  # See: rake update_version
4
4
  module Gem
5
- RubyGemsVersion = '0.9.2'
5
+ RubyGemsVersion = '0.9.3'
6
6
  end
@@ -6,9 +6,9 @@
6
6
 
7
7
  require 'rubygems/user_interaction'
8
8
  require 'rubygems/remote_fetcher'
9
+ require 'rubygems/digest/sha2'
9
10
 
10
11
  require 'forwardable'
11
- require 'digest/sha2'
12
12
  require 'time'
13
13
 
14
14
  module Gem
@@ -63,7 +63,7 @@ module Gem
63
63
  # List of directory paths (all ending in "../specifications").
64
64
  #
65
65
  def installed_spec_directories
66
- Gem.path.collect { |dir| File.join(dir, "specifications") }
66
+ Gem.path.collect { |dir| File.join(dir, "specifications") }
67
67
  end
68
68
 
69
69
  # Factory method to construct a source index instance for a
@@ -174,12 +174,12 @@ module Gem
174
174
  # The signature for the source index. Changes in the signature
175
175
  # indicate a change in the index.
176
176
  def index_signature
177
- Digest::SHA256.new(@gems.keys.sort.join(',')).to_s
177
+ Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
178
178
  end
179
179
 
180
180
  # The signature for the given gem specification.
181
181
  def gem_signature(gem_full_name)
182
- Digest::SHA256.new(@gems[gem_full_name].to_yaml).to_s
182
+ Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
183
183
  end
184
184
 
185
185
  def_delegators :@gems, :size, :length
@@ -508,6 +508,11 @@ module Gem
508
508
  File.join(installation_path, "gems", full_name)
509
509
  end
510
510
 
511
+ # The default (generated) file name of the gem.
512
+ def file_name
513
+ full_name + ".gem"
514
+ end
515
+
511
516
  # The root directory that the gem was installed into.
512
517
  #
513
518
  # return:: [String] the installation path
@@ -20,13 +20,13 @@ module Gem
20
20
  if(gem_data.size == 0) then
21
21
  raise VerificationError.new("Empty Gem file")
22
22
  end
23
- require 'md5'
24
- unless(gem_data =~ /MD5SUM/m)
25
- return # Don't worry about it...this sucks. Need to fix MD5 stuff for
26
- # new format
27
- # FIXME
23
+ require 'rubygems/digest/md5'
24
+ unless(gem_data =~ /MD5SUM/m)
25
+ return # Don't worry about it...this sucks. Need to fix MD5 stuff for
26
+ # new format
27
+ # FIXME
28
28
  end
29
- unless (MD5.md5(gem_data.gsub(/MD5SUM = "([a-z0-9]+)"/, "MD5SUM = \"" + ("F" * 32) + "\"")) == $1.to_s)
29
+ unless (Gem::MD5.hexdigest(gem_data.gsub(/MD5SUM = "([a-z0-9]+)"/, "MD5SUM = \"" + ("F" * 32) + "\"")) == $1.to_s)
30
30
  raise VerificationError.new("Invalid checksum for Gem file")
31
31
  end
32
32
  end
@@ -75,7 +75,7 @@ module Gem
75
75
  def alien
76
76
  require 'rubygems/installer'
77
77
  require 'find'
78
- require 'md5'
78
+ require 'rubygems/digest/md5'
79
79
  errors = {}
80
80
  Gem::SourceIndex.from_installed_gems.each do |gem_name, gem_spec|
81
81
  errors[gem_name] ||= []
@@ -97,7 +97,7 @@ module Gem
97
97
  # Found this file. Delete it from list
98
98
  installed_files.delete remove_leading_dot_dir(entry['path'])
99
99
  File.open(File.join(gem_directory, entry['path']), 'rb') do |f|
100
- unless MD5.md5(f.read).to_s == MD5.md5(data).to_s
100
+ unless Gem::MD5.hexdigest(f.read).to_s == Gem::MD5.hexdigest(data).to_s
101
101
  errors[gem_name] << ErrorData.new(entry['path'], "installed file doesn't match original from gem")
102
102
  end
103
103
  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,175 +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
118
-
119
- class PathItem < ConfigItem
120
- def config_type
121
- 'path'
122
- end
123
-
124
- private
47
+ include Enumerable
125
48
 
126
- def check(path)
127
- setup_rb_error "config: --#{@name} requires argument" unless path
128
- path[0,1] == '$' ? path : File.expand_path(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
129
58
  end
130
- end
131
59
 
132
- class ProgramItem < ConfigItem
133
- def config_type
134
- 'program'
135
- end
136
- end
60
+ attr_accessor :install_prefix
61
+ attr_accessor :config_opt
137
62
 
138
- class SelectItem < ConfigItem
139
- def initialize(name, template, default, desc)
140
- super
141
- @ok = template.split('/')
142
- end
63
+ attr_writer :verbose
143
64
 
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
- end
192
-
193
- include Enumerable
194
86
 
195
87
  def each(&block)
196
88
  @items.each(&block)
@@ -201,7 +93,7 @@ class ConfigTable_class
201
93
  end
202
94
 
203
95
  def lookup(name)
204
- @table[name] or raise ArgumentError, "no such config item: #{name}"
96
+ @table[name] or setup_rb_error "no such config item: #{name}"
205
97
  end
206
98
 
207
99
  def add(item)
@@ -216,24 +108,24 @@ class ConfigTable_class
216
108
  item
217
109
  end
218
110
 
219
- def new
220
- 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
221
115
  end
222
116
 
223
117
  def savefile
224
118
  '.config'
225
119
  end
226
120
 
227
- def load
121
+ def load_savefile
228
122
  begin
229
- t = dup()
230
123
  File.foreach(savefile()) do |line|
231
124
  k, v = *line.split(/=/, 2)
232
- t[k] = v.strip
125
+ self[k] = v.strip
233
126
  end
234
- t
235
127
  rescue Errno::ENOENT
236
- setup_rb_error $!.message + "#{File.basename($0)} config first"
128
+ setup_rb_error $!.message + "\n#{File.basename($0)} config first"
237
129
  end
238
130
  end
239
131
 
@@ -241,119 +133,151 @@ class ConfigTable_class
241
133
  @items.each {|i| i.value }
242
134
  File.open(savefile(), 'w') {|f|
243
135
  @items.each do |i|
244
- 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
245
137
  end
246
138
  }
247
- rescue Exception => e
248
- $stderr.puts "Exception thrown while trying to open #{savefile} in #{Dir.pwd}: #{e}... continuing"
249
139
  end
250
140
 
251
- def [](key)
252
- lookup(key).eval(self)
141
+ def load_standard_entries
142
+ standard_entries(@rbconfig).each do |ent|
143
+ add ent
144
+ end
253
145
  end
254
146
 
255
- def []=(key, val)
256
- lookup(key).set val
257
- 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
+ }
258
191
 
259
- 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
260
197
 
261
- c = ::Config::CONFIG
262
-
263
- rubypath = c['bindir'] + '/' + c['ruby_install_name']
264
-
265
- major = c['MAJOR'].to_i
266
- minor = c['MINOR'].to_i
267
- teeny = c['TEENY'].to_i
268
- version = "#{major}.#{minor}"
269
-
270
- # ruby ver. >= 1.4.4?
271
- newpath_p = ((major >= 2) or
272
- ((major == 1) and
273
- ((minor >= 5) or
274
- ((minor == 4) and (teeny >= 4)))))
275
-
276
- if c['rubylibdir']
277
- # V < 1.6.3
278
- _stdruby = c['rubylibdir']
279
- _siteruby = c['sitedir']
280
- _siterubyver = c['sitelibdir']
281
- _siterubyverarch = c['sitearchdir']
282
- elsif newpath_p
283
- # 1.4.4 <= V <= 1.6.3
284
- _stdruby = "$prefix/lib/ruby/#{version}"
285
- _siteruby = c['sitedir']
286
- _siterubyver = "$siteruby/#{version}"
287
- _siterubyverarch = "$siterubyver/#{c['arch']}"
288
- else
289
- # V < 1.4.4
290
- _stdruby = "$prefix/lib/ruby/#{version}"
291
- _siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
292
- _siterubyver = _siteruby
293
- _siterubyverarch = "$siterubyver/#{c['arch']}"
294
- end
295
- libdir = '-* dummy libdir *-'
296
- stdruby = '-* dummy rubylibdir *-'
297
- siteruby = '-* dummy site_ruby *-'
298
- siterubyver = '-* dummy site_ruby version *-'
299
- parameterize = lambda {|path|
300
- path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
301
- .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\
302
- .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\
303
- .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\
304
- .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
305
- }
306
- libdir = parameterize.call(c['libdir'])
307
- stdruby = parameterize.call(_stdruby)
308
- siteruby = parameterize.call(_siteruby)
309
- siterubyver = parameterize.call(_siterubyver)
310
- siterubyverarch = parameterize.call(_siterubyverarch)
311
-
312
- if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
313
- makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
314
- else
315
- makeprog = 'make'
316
- 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
317
275
 
318
- common_conf = [
319
- PathItem.new('prefix', 'path', c['prefix'],
320
- 'path prefix of target environment'),
321
- PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
322
- 'the directory for commands'),
323
- PathItem.new('libdir', 'path', libdir,
324
- 'the directory for libraries'),
325
- PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
326
- 'the directory for shared data'),
327
- PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
328
- 'the directory for man pages'),
329
- PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
330
- 'the directory for man pages'),
331
- PathItem.new('stdruby', 'path', stdruby,
332
- 'the directory for standard ruby libraries'),
333
- PathItem.new('siteruby', 'path', siteruby,
334
- 'the directory for version-independent aux ruby libraries'),
335
- PathItem.new('siterubyver', 'path', siterubyver,
336
- 'the directory for aux ruby libraries'),
337
- PathItem.new('siterubyverarch', 'path', siterubyverarch,
338
- 'the directory for aux ruby binaries'),
339
- PathItem.new('rbdir', 'path', '$siterubyver',
340
- 'the directory for ruby scripts'),
341
- PathItem.new('sodir', 'path', '$siterubyverarch',
342
- 'the directory for ruby extentions'),
343
- PathItem.new('rubypath', 'path', rubypath,
344
- 'the path to set to #! line'),
345
- ProgramItem.new('rubyprog', 'name', rubypath,
346
- 'the ruby program using for installation'),
347
- ProgramItem.new('makeprog', 'name', makeprog,
348
- 'the make program to compile ruby extentions'),
349
- SelectItem.new('shebang', 'all/ruby/never', 'ruby',
350
- 'shebang line (#!) editing mode'),
351
- BoolItem.new('without-ext', 'yes/no', 'no',
352
- 'does not compile/install ruby extentions')
353
- ]
354
- class ConfigTable_class # open again
355
276
  ALIASES = {
356
- 'std-ruby' => 'stdruby',
277
+ 'std-ruby' => 'librubyver',
278
+ 'stdruby' => 'librubyver',
279
+ 'rubylibdir' => 'librubyver',
280
+ 'archdir' => 'librubyverarch',
357
281
  'site-ruby-common' => 'siteruby', # For backward compatibility
358
282
  'site-ruby' => 'siterubyver', # For backward compatibility
359
283
  'bin-dir' => 'bindir',
@@ -367,78 +291,248 @@ class ConfigTable_class # open again
367
291
  'make-prog' => 'makeprog',
368
292
  'make' => 'makeprog'
369
293
  }
370
- end
371
- multipackage_conf = [
372
- PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
373
- 'package names that you want to install'),
374
- PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
375
- 'package names that you do not want to install')
376
- ]
377
- if multipackage_install?
378
- ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
379
- else
380
- ConfigTable = ConfigTable_class.new(common_conf)
381
- end
382
-
383
-
384
- module MetaConfigAPI
385
294
 
386
- def eval_file_ifexist(fname)
387
- 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/
388
302
  end
389
303
 
390
- def config_names
391
- 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]
392
307
  end
393
308
 
394
- def config?(name)
395
- ConfigTable.key?(name)
309
+ def dllext
310
+ @rbconfig['DLEXT']
396
311
  end
397
312
 
398
- def bool_config?(name)
399
- ConfigTable.lookup(name).config_type == 'bool'
313
+ def value_config?(name)
314
+ lookup(name).value?
400
315
  end
401
316
 
402
- def path_config?(name)
403
- ConfigTable.lookup(name).config_type == 'path'
404
- 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
405
325
 
406
- def value_config?(name)
407
- case ConfigTable.lookup(name).config_type
408
- 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?
409
337
  true
410
- else
411
- 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
412
357
  end
413
358
  end
414
359
 
415
- def add_config(item)
416
- 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
417
380
  end
418
381
 
419
- def add_bool_config(name, default, desc)
420
- 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
421
393
  end
422
394
 
423
- def add_path_config(name, default, desc)
424
- ConfigTable.add PathItem.new(name, 'path', default, desc)
395
+ class ProgramItem < Item
396
+ def config_type
397
+ 'program'
398
+ end
425
399
  end
426
400
 
427
- def set_config_default(name, default)
428
- 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
429
419
  end
430
420
 
431
- def remove_config(name)
432
- 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
433
449
  end
434
450
 
435
- 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
436
456
 
457
+ attr_reader :help_default
437
458
 
438
- #
439
- # File Operations
440
- #
459
+ def config_type
460
+ 'package'
461
+ end
462
+
463
+ private
441
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?
442
536
  module FileOperations
443
537
 
444
538
  def mkdir_p(dirname, prefix = nil)
@@ -446,7 +540,7 @@ module FileOperations
446
540
  $stderr.puts "mkdir -p #{dirname}" if verbose?
447
541
  return if no_harm?
448
542
 
449
- # does not check '/'... it's too abnormal case
543
+ # Does not check '/', it's too abnormal.
450
544
  dirs = File.expand_path(dirname).split(%r<(?=/)>)
451
545
  if /\A[a-z]:\z/i =~ dirs[0]
452
546
  disk = dirs.shift
@@ -458,49 +552,73 @@ module FileOperations
458
552
  end
459
553
  end
460
554
 
461
- def rm_f(fname)
462
- $stderr.puts "rm -f #{fname}" if verbose?
555
+ def rm_f(path)
556
+ $stderr.puts "rm -f #{path}" if verbose?
463
557
  return if no_harm?
464
-
465
- if File.exist?(fname) or File.symlink?(fname)
466
- File.chmod 0777, fname
467
- File.unlink fname
468
- end
558
+ force_remove_file path
469
559
  end
470
560
 
471
- def rm_rf(dn)
472
- $stderr.puts "rm -rf #{dn}" if verbose?
561
+ def rm_rf(path)
562
+ $stderr.puts "rm -rf #{path}" if verbose?
473
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
474
576
 
475
- Dir.chdir dn
476
- Dir.foreach('.') do |fn|
477
- next if fn == '.'
478
- next if fn == '..'
479
- if File.dir?(fn)
480
- verbose_off {
481
- rm_rf fn
482
- }
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
483
586
  else
484
- verbose_off {
485
- rm_f fn
486
- }
587
+ force_remove_file entpath
487
588
  end
488
589
  end
489
- Dir.chdir '..'
490
- Dir.rmdir dn
590
+ begin
591
+ Dir.rmdir path
592
+ rescue Errno::ENOTEMPTY
593
+ # directory may not be empty
594
+ end
491
595
  end
492
596
 
493
597
  def move_file(src, dest)
494
- File.unlink dest if File.exist?(dest)
598
+ force_remove_file dest
495
599
  begin
496
600
  File.rename src, dest
497
601
  rescue
498
- File.open(dest, 'wb') {|f| f.write File.binread(src) }
602
+ File.open(dest, 'wb') {|f|
603
+ f.write File.binread(src)
604
+ }
499
605
  File.chmod File.stat(src).mode, dest
500
606
  File.unlink src
501
607
  end
502
608
  end
503
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
+
504
622
  def install(from, dest, mode, prefix = nil)
505
623
  $stderr.puts "install #{from} #{dest}" if verbose?
506
624
  return if no_harm?
@@ -517,18 +635,13 @@ module FileOperations
517
635
  }
518
636
  File.chmod mode, realdest
519
637
 
520
- path = "#{objdir_root()}/InstalledFiles"
521
- begin
522
- File.open(path, 'a') {|f|
523
- if prefix
524
- f.puts realdest.sub(prefix, '')
525
- else
526
- f.puts realdest
527
- end
528
- }
529
- rescue Exception => e
530
- $stderr.puts "Exception thrown while trying to open #{path} in #{Dir.pwd}: #{e}... continuing"
531
- end
638
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
639
+ if prefix
640
+ f.puts realdest.sub(prefix, '')
641
+ else
642
+ f.puts realdest
643
+ end
644
+ }
532
645
  end
533
646
  end
534
647
 
@@ -537,66 +650,42 @@ module FileOperations
537
650
  new_content != File.binread(path)
538
651
  end
539
652
 
540
- def command(str)
541
- $stderr.puts str if verbose?
542
- 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"
543
657
  end
544
658
 
545
- def ruby(str)
546
- command config('rubyprog') + ' ' + str
659
+ def ruby(*args)
660
+ command config('rubyprog'), *args
547
661
  end
548
662
 
549
- def make(task = '')
550
- command config('makeprog') + ' ' + task
663
+ def make(task = nil)
664
+ command(*[config('makeprog'), task].compact)
551
665
  end
552
666
 
553
667
  def extdir?(dir)
554
- File.exist?(dir + '/MANIFEST')
668
+ File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
555
669
  end
556
670
 
557
- def all_files_in(dirname)
558
- Dir.open(dirname) {|d|
559
- 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}") }
560
674
  }
561
675
  end
562
676
 
563
- REJECT_DIRS = %w(
564
- CVS SCCS RCS CVS.adm .svn
565
- )
677
+ DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
566
678
 
567
- def all_dirs_in(dirname)
568
- Dir.open(dirname) {|d|
569
- 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
570
682
  }
571
683
  end
572
684
 
573
685
  end
574
686
 
575
687
 
576
- #
577
- # Main Installer
578
- #
579
-
580
- module HookUtils
581
-
582
- def run_hook(name)
583
- try_run_hook "#{curr_srcdir()}/#{name}" or
584
- try_run_hook "#{curr_srcdir()}/#{name}.rb"
585
- end
586
-
587
- def try_run_hook(fname)
588
- return false unless File.file?(fname)
589
- begin
590
- instance_eval File.read(fname), fname, 1
591
- rescue
592
- setup_rb_error "hook #{fname} failed:\n" + $!.message
593
- end
594
- true
595
- end
596
-
597
- end
598
-
599
-
688
+ # This module requires: #srcdir_root, #objdir_root, #relpath
600
689
  module HookScriptAPI
601
690
 
602
691
  def get_config(key)
@@ -605,6 +694,7 @@ module HookScriptAPI
605
694
 
606
695
  alias config get_config
607
696
 
697
+ # obsolete: use metaconfig to change configuration
608
698
  def set_config(key, val)
609
699
  @config[key] = val
610
700
  end
@@ -613,10 +703,6 @@ module HookScriptAPI
613
703
  # srcdir/objdir (works only in the package directory)
614
704
  #
615
705
 
616
- #abstract srcdir_root
617
- #abstract objdir_root
618
- #abstract relpath
619
-
620
706
  def curr_srcdir
621
707
  "#{srcdir_root()}/#{relpath()}"
622
708
  end
@@ -638,7 +724,7 @@ module HookScriptAPI
638
724
  end
639
725
 
640
726
  def srcfile?(path)
641
- File.file? srcfile(path)
727
+ File.file?(srcfile(path))
642
728
  end
643
729
 
644
730
  def srcentries(path = '.')
@@ -664,8 +750,8 @@ end
664
750
 
665
751
  class ToplevelInstaller
666
752
 
667
- Version = '3.3.1'
668
- Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
753
+ Version = '3.4.1'
754
+ Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
669
755
 
670
756
  TASKS = [
671
757
  [ 'all', 'do config, setup, then install' ],
@@ -673,27 +759,44 @@ class ToplevelInstaller
673
759
  [ 'show', 'shows current configuration' ],
674
760
  [ 'setup', 'compiles ruby extentions and others' ],
675
761
  [ 'install', 'installs files' ],
762
+ [ 'test', 'run all tests in test/' ],
676
763
  [ 'clean', "does `make clean' for each extention" ],
677
764
  [ 'distclean',"does `make distclean' for each extention" ]
678
765
  ]
679
766
 
680
767
  def ToplevelInstaller.invoke
681
- 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
682
774
  end
683
775
 
684
- @singleton = nil
685
-
686
- def ToplevelInstaller.instance
687
- @singleton ||= new(File.dirname($0))
688
- @singleton
776
+ def ToplevelInstaller.multipackage?
777
+ File.dir?(File.dirname($0) + '/packages')
689
778
  end
690
779
 
691
- 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
692
790
 
693
- def initialize(ardir_root)
694
- @config = nil
695
- @options = { 'verbose' => true }
791
+ def initialize(ardir_root, config)
696
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]
697
800
  end
698
801
 
699
802
  def inspect
@@ -704,14 +807,20 @@ class ToplevelInstaller
704
807
  run_metaconfigs
705
808
  case task = parsearg_global()
706
809
  when nil, 'all'
707
- @config = load_config('config')
708
810
  parsearg_config
709
811
  init_installers
710
812
  exec_config
711
813
  exec_setup
712
814
  exec_install
713
815
  else
714
- @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
715
824
  __send__ "parsearg_#{task}"
716
825
  init_installers
717
826
  __send__ "exec_#{task}"
@@ -719,25 +828,11 @@ class ToplevelInstaller
719
828
  end
720
829
 
721
830
  def run_metaconfigs
722
- eval_file_ifexist "#{@ardir}/metaconfig"
723
- end
724
-
725
- def load_config(task)
726
- case task
727
- when 'config'
728
- ConfigTable.new
729
- when 'clean', 'distclean'
730
- if File.exist?(ConfigTable.savefile)
731
- then ConfigTable.load
732
- else ConfigTable.new
733
- end
734
- else
735
- ConfigTable.load
736
- end
831
+ @config.load_script "#{@ardir}/metaconfig"
737
832
  end
738
833
 
739
834
  def init_installers
740
- @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
835
+ @installer = Installer.new(@config, @ardir, File.expand_path('.'))
741
836
  end
742
837
 
743
838
  #
@@ -761,78 +856,89 @@ class ToplevelInstaller
761
856
  #
762
857
 
763
858
  def parsearg_global
764
- valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
765
-
766
859
  while arg = ARGV.shift
767
860
  case arg
768
861
  when /\A\w+\z/
769
- setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
862
+ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
770
863
  return arg
771
-
772
864
  when '-q', '--quiet'
773
- @options['verbose'] = false
774
-
775
- when '--verbose'
776
- @options['verbose'] = true
777
-
778
- when '-h', '--help'
865
+ @config.verbose = false
866
+ when '--verbose'
867
+ @config.verbose = true
868
+ when '--help'
779
869
  print_usage $stdout
780
870
  exit 0
781
-
782
- when '-v', '--version'
871
+ when '--version'
783
872
  puts "#{File.basename($0)} version #{Version}"
784
873
  exit 0
785
-
786
874
  when '--copyright'
787
875
  puts Copyright
788
876
  exit 0
789
-
790
877
  else
791
878
  setup_rb_error "unknown global option '#{arg}'"
792
879
  end
793
880
  end
794
-
795
881
  nil
796
882
  end
797
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
798
891
 
799
892
  def parsearg_no_options
800
893
  unless ARGV.empty?
801
- 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(' ')}"
802
896
  end
803
897
  end
804
898
 
805
899
  alias parsearg_show parsearg_no_options
806
900
  alias parsearg_setup parsearg_no_options
901
+ alias parsearg_test parsearg_no_options
807
902
  alias parsearg_clean parsearg_no_options
808
903
  alias parsearg_distclean parsearg_no_options
809
904
 
810
905
  def parsearg_config
811
- re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
812
- @options['config-opt'] = []
813
-
906
+ evalopt = []
907
+ set = []
908
+ @config.config_opt = []
814
909
  while i = ARGV.shift
815
910
  if /\A--?\z/ =~ i
816
- @options['config-opt'] = ARGV.dup
911
+ @config.config_opt = ARGV.dup
817
912
  break
818
913
  end
819
- m = re.match(i) or setup_rb_error "config: unknown option #{i}"
820
- name, value = *m.to_a[1,2]
821
- @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)
822
928
  end
823
929
  end
824
930
 
825
931
  def parsearg_install
826
- @options['no-harm'] = false
827
- @options['install-prefix'] = ''
932
+ @config.no_harm = false
933
+ @config.install_prefix = ''
828
934
  while a = ARGV.shift
829
935
  case a
830
- when /\A--no-harm\z/
831
- @options['no-harm'] = true
832
- when /\A--prefix=(.*)\z/
833
- path = $1
936
+ when '--no-harm'
937
+ @config.no_harm = true
938
+ when /\A--prefix=/
939
+ path = a.split(/=/, 2)[1]
834
940
  path = File.expand_path(path) unless path[0,1] == '/'
835
- @options['install-prefix'] = path
941
+ @config.install_prefix = path
836
942
  else
837
943
  setup_rb_error "install: unknown option #{a}"
838
944
  end
@@ -854,8 +960,8 @@ class ToplevelInstaller
854
960
  out.puts 'Global options:'
855
961
  out.printf fmt, '-q,--quiet', 'suppress message outputs'
856
962
  out.printf fmt, ' --verbose', 'output messages verbosely'
857
- out.printf fmt, '-h,--help', 'print this message'
858
- 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'
859
965
  out.printf fmt, ' --copyright', 'print copyright and quit'
860
966
  out.puts
861
967
  out.puts 'Tasks:'
@@ -866,14 +972,14 @@ class ToplevelInstaller
866
972
  fmt = " %-24s %s [%s]\n"
867
973
  out.puts
868
974
  out.puts 'Options for CONFIG or ALL:'
869
- ConfigTable.each do |item|
975
+ @config.each do |item|
870
976
  out.printf fmt, item.help_opt, item.description, item.help_default
871
977
  end
872
978
  out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
873
979
  out.puts
874
980
  out.puts 'Options for INSTALL:'
875
981
  out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
876
- out.printf fmt, '--prefix=path', 'install path prefix', '$prefix'
982
+ out.printf fmt, '--prefix=path', 'install path prefix', ''
877
983
  out.puts
878
984
  end
879
985
 
@@ -894,9 +1000,13 @@ class ToplevelInstaller
894
1000
  @installer.exec_install
895
1001
  end
896
1002
 
1003
+ def exec_test
1004
+ @installer.exec_test
1005
+ end
1006
+
897
1007
  def exec_show
898
- ConfigTable.each do |i|
899
- 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?
900
1010
  end
901
1011
  end
902
1012
 
@@ -908,36 +1018,45 @@ class ToplevelInstaller
908
1018
  @installer.exec_distclean
909
1019
  end
910
1020
 
911
- end
1021
+ end # class ToplevelInstaller
912
1022
 
913
1023
 
914
1024
  class ToplevelInstallerMulti < ToplevelInstaller
915
1025
 
916
- include HookUtils
917
- include HookScriptAPI
918
1026
  include FileOperations
919
1027
 
920
- def initialize(ardir)
1028
+ def initialize(ardir_root, config)
921
1029
  super
922
- @packages = all_dirs_in("#{@ardir}/packages")
1030
+ @packages = directories_of("#{@ardir}/packages")
923
1031
  raise 'no package exists' if @packages.empty?
1032
+ @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
924
1033
  end
925
1034
 
926
1035
  def run_metaconfigs
927
- eval_file_ifexist "#{@ardir}/metaconfig"
1036
+ @config.load_script "#{@ardir}/metaconfig", self
928
1037
  @packages.each do |name|
929
- eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
1038
+ @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
930
1039
  end
931
1040
  end
932
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
+
933
1053
  def init_installers
934
1054
  @installers = {}
935
1055
  @packages.each do |pack|
936
- @installers[pack] = Installer.new(@config, @options,
1056
+ @installers[pack] = Installer.new(@config,
937
1057
  "#{@ardir}/packages/#{pack}",
938
1058
  "packages/#{pack}")
939
1059
  end
940
-
941
1060
  with = extract_selection(config('with'))
942
1061
  without = extract_selection(config('without'))
943
1062
  @selected = @installers.keys.select {|name|
@@ -961,21 +1080,6 @@ class ToplevelInstallerMulti < ToplevelInstaller
961
1080
  f.puts
962
1081
  end
963
1082
 
964
- #
965
- # multi-package metaconfig API
966
- #
967
-
968
- attr_reader :packages
969
-
970
- def declare_packages(list)
971
- raise 'package list is empty' if list.empty?
972
- list.each do |name|
973
- raise "directory packages/#{name} does not exist"\
974
- unless File.dir?("#{@ardir}/packages/#{name}")
975
- end
976
- @packages = list
977
- end
978
-
979
1083
  #
980
1084
  # Task Handlers
981
1085
  #
@@ -999,15 +1103,21 @@ class ToplevelInstallerMulti < ToplevelInstaller
999
1103
  run_hook 'post-install'
1000
1104
  end
1001
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
+
1002
1112
  def exec_clean
1003
- rm_f ConfigTable.savefile
1113
+ rm_f @config.savefile
1004
1114
  run_hook 'pre-clean'
1005
1115
  each_selected_installers {|inst| inst.exec_clean }
1006
1116
  run_hook 'post-clean'
1007
1117
  end
1008
1118
 
1009
1119
  def exec_distclean
1010
- rm_f ConfigTable.savefile
1120
+ rm_f @config.savefile
1011
1121
  run_hook 'pre-distclean'
1012
1122
  each_selected_installers {|inst| inst.exec_distclean }
1013
1123
  run_hook 'post-distclean'
@@ -1020,7 +1130,7 @@ class ToplevelInstallerMulti < ToplevelInstaller
1020
1130
  def each_selected_installers
1021
1131
  Dir.mkdir 'packages' unless File.dir?('packages')
1022
1132
  @selected.each do |pack|
1023
- $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1133
+ $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1024
1134
  Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1025
1135
  Dir.chdir "packages/#{pack}"
1026
1136
  yield @installers[pack]
@@ -1028,28 +1138,32 @@ class ToplevelInstallerMulti < ToplevelInstaller
1028
1138
  end
1029
1139
  end
1030
1140
 
1141
+ def run_hook(id)
1142
+ @root_installer.run_hook id
1143
+ end
1144
+
1145
+ # module FileOperations requires this
1031
1146
  def verbose?
1032
- @options['verbose']
1147
+ @config.verbose?
1033
1148
  end
1034
1149
 
1150
+ # module FileOperations requires this
1035
1151
  def no_harm?
1036
- @options['no-harm']
1152
+ @config.no_harm?
1037
1153
  end
1038
1154
 
1039
- end
1155
+ end # class ToplevelInstallerMulti
1040
1156
 
1041
1157
 
1042
1158
  class Installer
1043
1159
 
1044
- FILETYPES = %w( bin lib ext data )
1160
+ FILETYPES = %w( bin lib ext data conf man )
1045
1161
 
1046
- include HookScriptAPI
1047
- include HookUtils
1048
1162
  include FileOperations
1163
+ include HookScriptAPI
1049
1164
 
1050
- def initialize(config, opt, srcroot, objroot)
1165
+ def initialize(config, srcroot, objroot)
1051
1166
  @config = config
1052
- @options = opt
1053
1167
  @srcdir = File.expand_path(srcroot)
1054
1168
  @objdir = File.expand_path(objroot)
1055
1169
  @currdir = '.'
@@ -1059,6 +1173,9 @@ class Installer
1059
1173
  "#<#{self.class} #{File.basename(@srcdir)}>"
1060
1174
  end
1061
1175
 
1176
+ def noop(rel)
1177
+ end
1178
+
1062
1179
  #
1063
1180
  # Hook Script API base methods
1064
1181
  #
@@ -1076,23 +1193,25 @@ class Installer
1076
1193
  end
1077
1194
 
1078
1195
  #
1079
- # configs/options
1196
+ # Config Access
1080
1197
  #
1081
1198
 
1082
- def no_harm?
1083
- @options['no-harm']
1199
+ # module FileOperations requires this
1200
+ def verbose?
1201
+ @config.verbose?
1084
1202
  end
1085
1203
 
1086
- def verbose?
1087
- @options['verbose']
1204
+ # module FileOperations requires this
1205
+ def no_harm?
1206
+ @config.no_harm?
1088
1207
  end
1089
1208
 
1090
1209
  def verbose_off
1091
1210
  begin
1092
- save, @options['verbose'] = @options['verbose'], false
1211
+ save, @config.verbose = @config.verbose?, false
1093
1212
  yield
1094
1213
  ensure
1095
- @options['verbose'] = save
1214
+ @config.verbose = save
1096
1215
  end
1097
1216
  end
1098
1217
 
@@ -1104,22 +1223,19 @@ class Installer
1104
1223
  exec_task_traverse 'config'
1105
1224
  end
1106
1225
 
1107
- def config_dir_bin(rel)
1108
- end
1109
-
1110
- def config_dir_lib(rel)
1111
- end
1226
+ alias config_dir_bin noop
1227
+ alias config_dir_lib noop
1112
1228
 
1113
1229
  def config_dir_ext(rel)
1114
1230
  extconf if extdir?(curr_srcdir())
1115
1231
  end
1116
1232
 
1117
- def extconf
1118
- opt = @options['config-opt'].join(' ')
1119
- command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
1120
- end
1233
+ alias config_dir_data noop
1234
+ alias config_dir_conf noop
1235
+ alias config_dir_man noop
1121
1236
 
1122
- def config_dir_data(rel)
1237
+ def extconf
1238
+ ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1123
1239
  end
1124
1240
 
1125
1241
  #
@@ -1131,39 +1247,90 @@ class Installer
1131
1247
  end
1132
1248
 
1133
1249
  def setup_dir_bin(rel)
1134
- all_files_in(curr_srcdir()).each do |fname|
1135
- adjust_shebang "#{curr_srcdir()}/#{fname}"
1250
+ files_of(curr_srcdir()).each do |fname|
1251
+ update_shebang_line "#{curr_srcdir()}/#{fname}"
1136
1252
  end
1137
1253
  end
1138
1254
 
1139
- 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)
1140
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)
1141
1299
  tmpfile = File.basename(path) + '.tmp'
1142
1300
  begin
1143
- File.open(path, 'rb') {|r|
1144
- first = r.gets
1145
- return unless File.basename(config('rubypath')) == 'ruby'
1146
- return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
1147
- $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1148
- File.open(tmpfile, 'wb') {|w|
1149
- w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1150
- w.write r.read
1151
- }
1152
- }
1153
- move_file tmpfile, File.basename(path)
1301
+ File.open(tmpfile, 'wb', &block)
1302
+ File.rename tmpfile, File.basename(path)
1154
1303
  ensure
1155
1304
  File.unlink tmpfile if File.exist?(tmpfile)
1156
1305
  end
1157
1306
  end
1158
1307
 
1159
- def setup_dir_lib(rel)
1160
- 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
1161
1317
 
1162
- def setup_dir_ext(rel)
1163
- make if extdir?(curr_srcdir())
1164
- 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
1165
1327
 
1166
- 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
1167
1334
  end
1168
1335
 
1169
1336
  #
@@ -1176,63 +1343,77 @@ class Installer
1176
1343
  end
1177
1344
 
1178
1345
  def install_dir_bin(rel)
1179
- install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
1346
+ install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1180
1347
  end
1181
1348
 
1182
1349
  def install_dir_lib(rel)
1183
- install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
1350
+ install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
1184
1351
  end
1185
1352
 
1186
1353
  def install_dir_ext(rel)
1187
1354
  return unless extdir?(curr_srcdir())
1188
- install_files ruby_extentions('.'),
1355
+ install_files rubyextentions('.'),
1189
1356
  "#{config('sodir')}/#{File.dirname(rel)}",
1190
1357
  0555
1191
1358
  end
1192
1359
 
1193
1360
  def install_dir_data(rel)
1194
- 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
1195
1372
  end
1196
1373
 
1197
1374
  def install_files(list, dest, mode)
1198
- mkdir_p dest, @options['install-prefix']
1375
+ mkdir_p dest, @config.install_prefix
1199
1376
  list.each do |fname|
1200
- install fname, dest, mode, @options['install-prefix']
1377
+ install fname, dest, mode, @config.install_prefix
1201
1378
  end
1202
1379
  end
1203
1380
 
1204
- def ruby_scripts
1205
- collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
1381
+ def libfiles
1382
+ glob_reject(%w(*.y *.output), targetfiles())
1206
1383
  end
1207
-
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
+
1208
1406
  # picked up many entries from cvs-1.11.1/src/ignore.c
1209
- reject_patterns = %w(
1407
+ JUNK_FILES = %w(
1210
1408
  core RCSLOG tags TAGS .make.state
1211
1409
  .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1212
1410
  *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1213
1411
 
1214
1412
  *.org *.in .*
1215
1413
  )
1216
- mapping = {
1217
- '.' => '\.',
1218
- '$' => '\$',
1219
- '#' => '\#',
1220
- '*' => '.*'
1221
- }
1222
- REJECT_PATTERNS = Regexp.new('\A(?:' +
1223
- reject_patterns.map {|pat|
1224
- pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1225
- }.join('|') +
1226
- ')\z')
1227
-
1228
- def collect_filenames_auto
1229
- mapdir((existfiles() - hookfiles()).reject {|fname|
1230
- REJECT_PATTERNS =~ fname
1231
- })
1232
- end
1233
1414
 
1234
1415
  def existfiles
1235
- all_files_in(curr_srcdir()) | all_files_in('.')
1416
+ glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1236
1417
  end
1237
1418
 
1238
1419
  def hookfiles
@@ -1241,24 +1422,49 @@ class Installer
1241
1422
  }.flatten
1242
1423
  end
1243
1424
 
1244
- def mapdir(filelist)
1245
- filelist.map {|fname|
1246
- if File.exist?(fname) # objdir
1247
- fname
1248
- else # srcdir
1249
- File.join(curr_srcdir(), fname)
1250
- end
1251
- }
1425
+ def glob_select(pat, ents)
1426
+ re = globs2re([pat])
1427
+ ents.select {|ent| re =~ ent }
1252
1428
  end
1253
1429
 
1254
- def ruby_extentions(dir)
1255
- Dir.open(dir) {|d|
1256
- ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
1257
- if ents.empty?
1258
- setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1259
- end
1260
- return ents
1261
- }
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
1262
1468
  end
1263
1469
 
1264
1470
  #
@@ -1267,53 +1473,51 @@ class Installer
1267
1473
 
1268
1474
  def exec_clean
1269
1475
  exec_task_traverse 'clean'
1270
- rm_f ConfigTable.savefile
1476
+ rm_f @config.savefile
1271
1477
  rm_f 'InstalledFiles'
1272
1478
  end
1273
1479
 
1274
- def clean_dir_bin(rel)
1275
- end
1276
-
1277
- def clean_dir_lib(rel)
1278
- 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
1279
1485
 
1280
1486
  def clean_dir_ext(rel)
1281
1487
  return unless extdir?(curr_srcdir())
1282
1488
  make 'clean' if File.file?('Makefile')
1283
1489
  end
1284
1490
 
1285
- def clean_dir_data(rel)
1286
- end
1287
-
1288
1491
  #
1289
1492
  # TASK distclean
1290
1493
  #
1291
1494
 
1292
1495
  def exec_distclean
1293
1496
  exec_task_traverse 'distclean'
1294
- rm_f ConfigTable.savefile
1497
+ rm_f @config.savefile
1295
1498
  rm_f 'InstalledFiles'
1296
1499
  end
1297
1500
 
1298
- def distclean_dir_bin(rel)
1299
- end
1300
-
1301
- def distclean_dir_lib(rel)
1302
- end
1501
+ alias distclean_dir_bin noop
1502
+ alias distclean_dir_lib noop
1303
1503
 
1304
1504
  def distclean_dir_ext(rel)
1305
1505
  return unless extdir?(curr_srcdir())
1306
1506
  make 'distclean' if File.file?('Makefile')
1307
1507
  end
1308
1508
 
1509
+ alias distclean_dir_data noop
1510
+ alias distclean_dir_conf noop
1511
+ alias distclean_dir_man noop
1512
+
1309
1513
  #
1310
- # lib
1514
+ # Traversing
1311
1515
  #
1312
1516
 
1313
1517
  def exec_task_traverse(task)
1314
1518
  run_hook "pre-#{task}"
1315
1519
  FILETYPES.each do |type|
1316
- if config('without-ext') == 'yes' and type == 'ext'
1520
+ if type == 'ext' and config('without-ext') == 'yes'
1317
1521
  $stderr.puts 'skipping ext/* by user option' if verbose?
1318
1522
  next
1319
1523
  end
@@ -1326,7 +1530,7 @@ class Installer
1326
1530
  dive_into(rel) {
1327
1531
  run_hook "pre-#{task}"
1328
1532
  __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1329
- all_dirs_in(curr_srcdir()).each do |d|
1533
+ directories_of(curr_srcdir()).each do |d|
1330
1534
  traverse task, "#{rel}/#{d}", mid
1331
1535
  end
1332
1536
  run_hook "post-#{task}"
@@ -1348,16 +1552,30 @@ class Installer
1348
1552
  @currdir = File.dirname(rel)
1349
1553
  end
1350
1554
 
1351
- 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
1352
1571
 
1572
+ def setup_rb_error(msg)
1573
+ raise SetupError, msg
1574
+ end
1353
1575
 
1354
1576
  if $0 == __FILE__
1355
1577
  begin
1356
- if multipackage_install?
1357
- ToplevelInstallerMulti.invoke
1358
- else
1359
- ToplevelInstaller.invoke
1360
- end
1578
+ ToplevelInstaller.invoke
1361
1579
  rescue SetupError
1362
1580
  raise if $DEBUG
1363
1581
  $stderr.puts $!.message