Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/tags/rel_0-14-4/actionwebservice/setup.rb

Revision 3068, 29.6 kB (checked in by marcel, 3 years ago)

Apply [3067] to stable. Update from LGPL to MIT license as per Minero Aoki's permission.

Line 
1 #
2 # setup.rb
3 #
4 # Copyright (c) 2000-2004 Minero Aoki
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #
25 # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
26 # with permission of Minero Aoki.
27
28 #
29
30 unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
31   module Enumerable
32     alias map collect
33   end
34 end
35
36 unless File.respond_to?(:read)   # Ruby 1.6
37   def File.read(fname)
38     open(fname) {|f|
39       return f.read
40     }
41   end
42 end
43
44 def File.binread(fname)
45   open(fname, 'rb') {|f|
46     return f.read
47   }
48 end
49
50 # for corrupted windows stat(2)
51 def File.dir?(path)
52   File.directory?((path[-1,1] == '/') ? path : path + '/')
53 end
54
55
56 class SetupError < StandardError; end
57
58 def setup_rb_error(msg)
59   raise SetupError, msg
60 end
61
62 #
63 # Config
64 #
65
66 if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
67   ARGV.delete(arg)
68   require arg.split(/=/, 2)[1]
69   $".push 'rbconfig.rb'
70 else
71   require 'rbconfig'
72 end
73
74 def multipackage_install?
75   FileTest.directory?(File.dirname($0) + '/packages')
76 end
77
78
79 class ConfigItem
80   def initialize(name, template, default, desc)
81     @name = name.freeze
82     @template = template
83     @value = default
84     @default = default.dup.freeze
85     @description = desc
86   end
87
88   attr_reader :name
89   attr_reader :description
90
91   attr_accessor :default
92   alias help_default default
93
94   def help_opt
95     "--#{@name}=#{@template}"
96   end
97
98   def value
99     @value
100   end
101
102   def eval(table)
103     @value.gsub(%r<\$([^/]+)>) { table[$1] }
104   end
105
106   def set(val)
107     @value = check(val)
108   end
109
110   private
111
112   def check(val)
113     setup_rb_error "config: --#{name} requires argument" unless val
114     val
115   end
116 end
117
118 class BoolItem < ConfigItem
119   def config_type
120     'bool'
121   end
122
123   def help_opt
124     "--#{@name}"
125   end
126
127   private
128
129   def check(val)
130     return 'yes' unless val
131     unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
132       setup_rb_error "config: --#{@name} accepts only yes/no for argument"
133     end
134     (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
135   end
136 end
137
138 class PathItem < ConfigItem
139   def config_type
140     'path'
141   end
142
143   private
144
145   def check(path)
146     setup_rb_error "config: --#{@name} requires argument"  unless path
147     path[0,1] == '$' ? path : File.expand_path(path)
148   end
149 end
150
151 class ProgramItem < ConfigItem
152   def config_type
153     'program'
154   end
155 end
156
157 class SelectItem < ConfigItem
158   def initialize(name, template, default, desc)
159     super
160     @ok = template.split('/')
161   end
162
163   def config_type
164     'select'
165   end
166
167   private
168
169   def check(val)
170     unless @ok.include?(val.strip)
171       setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
172     end
173     val.strip
174   end
175 end
176
177 class PackageSelectionItem < ConfigItem
178   def initialize(name, template, default, help_default, desc)
179     super name, template, default, desc
180     @help_default = help_default
181   end
182
183   attr_reader :help_default
184
185   def config_type
186     'package'
187   end
188
189   private
190
191   def check(val)
192     unless File.dir?("packages/#{val}")
193       setup_rb_error "config: no such package: #{val}"
194     end
195     val
196   end
197 end
198
199 class ConfigTable_class
200
201   def initialize(items)
202     @items = items
203     @table = {}
204     items.each do |i|
205       @table[i.name] = i
206     end
207     ALIASES.each do |ali, name|
208       @table[ali] = @table[name]
209     end
210   end
211
212   include Enumerable
213
214   def each(&block)
215     @items.each(&block)
216   end
217
218   def key?(name)
219     @table.key?(name)
220   end
221
222   def lookup(name)
223     @table[name] or raise ArgumentError, "no such config item: #{name}"
224   end
225
226   def add(item)
227     @items.push item
228     @table[item.name] = item
229   end
230
231   def remove(name)
232     item = lookup(name)
233     @items.delete_if {|i| i.name == name }
234     @table.delete_if {|name, i| i.name == name }
235     item
236   end
237
238   def new
239     dup()
240   end
241
242   def savefile
243     '.config'
244   end
245
246   def load
247     begin
248       t = dup()
249       File.foreach(savefile()) do |line|
250         k, v = *line.split(/=/, 2)
251         t[k] = v.strip
252       end
253       t
254     rescue Errno::ENOENT
255       setup_rb_error $!.message + "#{File.basename($0)} config first"
256     end
257   end
258
259   def save
260     @items.each {|i| i.value }
261     File.open(savefile(), 'w') {|f|
262       @items.each do |i|
263         f.printf "%s=%s\n", i.name, i.value if i.value
264       end
265     }
266   end
267
268   def [](key)
269     lookup(key).eval(self)
270   end
271
272   def []=(key, val)
273     lookup(key).set val
274   end
275
276 end
277
278 c = ::Config::CONFIG
279
280 rubypath = c['bindir'] + '/' + c['ruby_install_name']
281
282 major = c['MAJOR'].to_i
283 minor = c['MINOR'].to_i
284 teeny = c['TEENY'].to_i
285 version = "#{major}.#{minor}"
286
287 # ruby ver. >= 1.4.4?
288 newpath_p = ((major >= 2) or
289              ((major == 1) and
290               ((minor >= 5) or
291                ((minor == 4) and (teeny >= 4)))))
292
293 if c['rubylibdir']
294   # V < 1.6.3
295   _stdruby         = c['rubylibdir']
296   _siteruby        = c['sitedir']
297   _siterubyver     = c['sitelibdir']
298   _siterubyverarch = c['sitearchdir']
299 elsif newpath_p
300   # 1.4.4 <= V <= 1.6.3
301   _stdruby         = "$prefix/lib/ruby/#{version}"
302   _siteruby        = c['sitedir']
303   _siterubyver     = "$siteruby/#{version}"
304   _siterubyverarch = "$siterubyver/#{c['arch']}"
305 else
306   # V < 1.4.4
307   _stdruby         = "$prefix/lib/ruby/#{version}"
308   _siteruby        = "$prefix/lib/ruby/#{version}/site_ruby"
309   _siterubyver     = _siteruby
310   _siterubyverarch = "$siterubyver/#{c['arch']}"
311 end
312 libdir = '-* dummy libdir *-'
313 stdruby = '-* dummy rubylibdir *-'
314 siteruby = '-* dummy site_ruby *-'
315 siterubyver = '-* dummy site_ruby version *-'
316 parameterize = lambda {|path|
317   path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
318       .sub(/\A#{Regexp.quote(libdir)}/,      '$libdir')\
319       .sub(/\A#{Regexp.quote(stdruby)}/,     '$stdruby')\
320       .sub(/\A#{Regexp.quote(siteruby)}/,    '$siteruby')\
321       .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
322 }
323 libdir          = parameterize.call(c['libdir'])
324 stdruby         = parameterize.call(_stdruby)
325 siteruby        = parameterize.call(_siteruby)
326 siterubyver     = parameterize.call(_siterubyver)
327 siterubyverarch = parameterize.call(_siterubyverarch)
328
329 if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
330   makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
331 else
332   makeprog = 'make'
333 end
334
335 common_conf = [
336   PathItem.new('prefix', 'path', c['prefix'],
337                'path prefix of target environment'),
338   PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
339                'the directory for commands'),
340   PathItem.new('libdir', 'path', libdir,
341                'the directory for libraries'),
342   PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
343                'the directory for shared data'),
344   PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
345                'the directory for man pages'),
346   PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
347                'the directory for man pages'),
348   PathItem.new('stdruby', 'path', stdruby,
349                'the directory for standard ruby libraries'),
350   PathItem.new('siteruby', 'path', siteruby,
351       'the directory for version-independent aux ruby libraries'),
352   PathItem.new('siterubyver', 'path', siterubyver,
353                'the directory for aux ruby libraries'),
354   PathItem.new('siterubyverarch', 'path', siterubyverarch,
355                'the directory for aux ruby binaries'),
356   PathItem.new('rbdir', 'path', '$siterubyver',
357                'the directory for ruby scripts'),
358   PathItem.new('sodir', 'path', '$siterubyverarch',
359                'the directory for ruby extentions'),
360   PathItem.new('rubypath', 'path', rubypath,
361                'the path to set to #! line'),
362   ProgramItem.new('rubyprog', 'name', rubypath,
363                   'the ruby program using for installation'),
364   ProgramItem.new('makeprog', 'name', makeprog,
365                   'the make program to compile ruby extentions'),
366   SelectItem.new('shebang', 'all/ruby/never', 'ruby',
367                  'shebang line (#!) editing mode'),
368   BoolItem.new('without-ext', 'yes/no', 'no',
369                'does not compile/install ruby extentions')
370 ]
371 class ConfigTable_class   # open again
372   ALIASES = {
373     'std-ruby'         => 'stdruby',
374     'site-ruby-common' => 'siteruby',     # For backward compatibility
375     'site-ruby'        => 'siterubyver',  # For backward compatibility
376     'bin-dir'          => 'bindir',
377     'bin-dir'          => 'bindir',
378     'rb-dir'           => 'rbdir',
379     'so-dir'           => 'sodir',
380     'data-dir'         => 'datadir',
381     'ruby-path'        => 'rubypath',
382     'ruby-prog'        => 'rubyprog',
383     'ruby'             => 'rubyprog',
384     'make-prog'        => 'makeprog',
385     'make'             => 'makeprog'
386   }
387 end
388 multipackage_conf = [
389   PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
390                            'package names that you want to install'),
391   PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
392                            'package names that you do not want to install')
393 ]
394 if multipackage_install?
395   ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
396 else
397   ConfigTable = ConfigTable_class.new(common_conf)
398 end
399
400
401 module MetaConfigAPI
402
403   def eval_file_ifexist(fname)
404     instance_eval File.read(fname), fname, 1 if File.file?(fname)
405   end
406
407   def config_names
408     ConfigTable.map {|i| i.name }
409   end
410
411   def config?(name)
412     ConfigTable.key?(name)
413   end
414
415   def bool_config?(name)
416     ConfigTable.lookup(name).config_type == 'bool'
417   end
418
419   def path_config?(name)
420     ConfigTable.lookup(name).config_type == 'path'
421   end
422
423   def value_config?(name)
424     case ConfigTable.lookup(name).config_type
425     when 'bool', 'path'
426       true
427     else
428       false
429     end
430   end
431
432   def add_config(item)
433     ConfigTable.add item
434   end
435
436   def add_bool_config(name, default, desc)
437     ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
438   end
439
440   def add_path_config(name, default, desc)
441     ConfigTable.add PathItem.new(name, 'path', default, desc)
442   end
443
444   def set_config_default(name, default)
445     ConfigTable.lookup(name).default = default
446   end
447
448   def remove_config(name)
449     ConfigTable.remove(name)
450   end
451
452 end
453
454
455 #
456 # File Operations
457 #
458
459 module FileOperations
460
461   def mkdir_p(dirname, prefix = nil)
462     dirname = prefix + File.expand_path(dirname) if prefix
463     $stderr.puts "mkdir -p #{dirname}" if verbose?
464     return if no_harm?
465
466     # does not check '/'... it's too abnormal case
467     dirs = File.expand_path(dirname).split(%r<(?=/)>)
468     if /\A[a-z]:\z/i =~ dirs[0]
469       disk = dirs.shift
470       dirs[0] = disk + dirs[0]
471     end
472     dirs.each_index do |idx|
473       path = dirs[0..idx].join('')
474       Dir.mkdir path unless File.dir?(path)
475     end
476   end
477
478   def rm_f(fname)
479     $stderr.puts "rm -f #{fname}" if verbose?
480     return if no_harm?
481
482     if File.exist?(fname) or File.symlink?(fname)
483       File.chmod 0777, fname
484       File.unlink fname
485     end
486   end
487
488   def rm_rf(dn)
489     $stderr.puts "rm -rf #{dn}" if verbose?
490     return if no_harm?
491
492     Dir.chdir dn
493     Dir.foreach('.') do |fn|
494       next if fn == '.'
495       next if fn == '..'
496       if File.dir?(fn)
497         verbose_off {
498           rm_rf fn
499         }
500       else
501         verbose_off {
502           rm_f fn
503         }
504       end
505     end
506     Dir.chdir '..'
507     Dir.rmdir dn
508   end
509
510   def move_file(src, dest)
511     File.unlink dest if File.exist?(dest)
512     begin
513       File.rename src, dest
514     rescue
515       File.open(dest, 'wb') {|f| f.write File.binread(src) }
516       File.chmod File.stat(src).mode, dest
517       File.unlink src
518     end
519   end
520
521   def install(from, dest, mode, prefix = nil)
522     $stderr.puts "install #{from} #{dest}" if verbose?
523     return if no_harm?
524
525     realdest = prefix ? prefix + File.expand_path(dest) : dest
526     realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
527     str = File.binread(from)
528     if diff?(str, realdest)
529       verbose_off {
530         rm_f realdest if File.exist?(realdest)
531       }
532       File.open(realdest, 'wb') {|f|
533         f.write str
534       }
535       File.chmod mode, realdest
536
537       File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
538         if prefix
539           f.puts realdest.sub(prefix, '')
540         else
541           f.puts realdest
542         end
543       }
544     end
545   end
546
547   def diff?(new_content, path)
548     return true unless File.exist?(path)
549     new_content != File.binread(path)
550   end
551
552   def command(str)
553     $stderr.puts str if verbose?
554     system str or raise RuntimeError, "'system #{str}' failed"
555   end
556
557   def ruby(str)
558     command config('rubyprog') + ' ' + str
559   end
560  
561   def make(task = '')
562     command config('makeprog') + ' ' + task
563   end
564
565   def extdir?(dir)
566     File.exist?(dir + '/MANIFEST')
567   end
568
569   def all_files_in(dirname)
570     Dir.open(dirname) {|d|
571       return d.select {|ent| File.file?("#{dirname}/#{ent}") }
572     }
573   end
574
575   REJECT_DIRS = %w(
576     CVS SCCS RCS CVS.adm .svn
577   )
578
579   def all_dirs_in(dirname)
580     Dir.open(dirname) {|d|
581       return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
582     }
583   end
584
585 end
586
587
588 #
589 # Main Installer
590 #
591
592 module HookUtils
593
594   def run_hook(name)