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

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

Revision 2763, 28.6 kB (checked in by david, 3 years ago)

Authentic 0.14.2 tag

Line 
1 #
2 # setup.rb
3 #
4 # Copyright (c) 2000-2004 Minero Aoki
5 #
6 # This program is free software.
7 # You can distribute/modify this program under the terms of
8 # the GNU LGPL, Lesser General Public License version 2.1.
9 #
10
11 unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
12   module Enumerable
13     alias map collect
14   end
15 end
16
17 unless File.respond_to?(:read)   # Ruby 1.6
18   def File.read(fname)
19     open(fname) {|f|
20       return f.read
21     }
22   end
23 end
24
25 def File.binread(fname)
26   open(fname, 'rb') {|f|
27     return f.read
28   }
29 end
30
31 # for corrupted windows stat(2)
32 def File.dir?(path)
33   File.directory?((path[-1,1] == '/') ? path : path + '/')
34 end
35
36
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
109
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
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
131
132 class ProgramItem < ConfigItem
133   def config_type
134     'program'
135   end
136 end
137
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'
146   end
147
148   private
149
150   def check(val)
151     unless @ok.include?(val.strip)
152       setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
153     end
154     val.strip
155   end
156 end
157
158 class PackageSelectionItem < ConfigItem
159   def initialize(name, template, default, help_default, desc)
160     super name, template, default, desc
161     @help_default = help_default
162   end
163
164   attr_reader :help_default
165
166   def config_type
167     'package'
168   end
169
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
177   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
195   def each(&block)
196     @items.each(&block)
197   end
198
199   def key?(name)
200     @table.key?(name)
201   end
202
203   def lookup(name)
204     @table[name] or raise ArgumentError, "no such config item: #{name}"
205   end
206
207   def add(item)
208     @items.push item
209     @table[item.name] = item
210   end
211
212   def remove(name)
213     item = lookup(name)
214     @items.delete_if {|i| i.name == name }
215     @table.delete_if {|name, i| i.name == name }
216     item
217   end
218
219   def new
220     dup()
221   end
222
223   def savefile
224     '.config'
225   end
226
227   def load
228     begin
229       t = dup()
230       File.foreach(savefile()) do |line|
231         k, v = *line.split(/=/, 2)
232         t[k] = v.strip
233       end
234       t
235     rescue Errno::ENOENT
236       setup_rb_error $!.message + "#{File.basename($0)} config first"
237     end
238   end
239
240   def save
241     @items.each {|i| i.value }
242     File.open(savefile(), 'w') {|f|
243       @items.each do |i|
244         f.printf "%s=%s\n", i.name, i.value if i.value
245       end
246     }
247   end
248
249   def [](key)
250     lookup(key).eval(self)
251   end
252
253   def []=(key, val)
254     lookup(key).set val
255   end
256
257 end
258
259 c = ::Config::CONFIG
260
261 rubypath = c['bindir'] + '/' + c['ruby_install_name']
262
263 major = c['MAJOR'].to_i
264 minor = c['MINOR'].to_i
265 teeny = c['TEENY'].to_i
266 version = "#{major}.#{minor}"
267
268 # ruby ver. >= 1.4.4?
269 newpath_p = ((major >= 2) or
270              ((major == 1) and
271               ((minor >= 5) or
272                ((minor == 4) and (teeny >= 4)))))
273
274 if c['rubylibdir']
275   # V < 1.6.3
276   _stdruby         = c['rubylibdir']
277   _siteruby        = c['sitedir']
278   _siterubyver     = c['sitelibdir']
279   _siterubyverarch = c['sitearchdir']
280 elsif newpath_p
281   # 1.4.4 <= V <= 1.6.3
282   _stdruby         = "$prefix/lib/ruby/#{version}"
283   _siteruby        = c['sitedir']
284   _siterubyver     = "$siteruby/#{version}"
285   _siterubyverarch = "$siterubyver/#{c['arch']}"
286 else
287   # V < 1.4.4
288   _stdruby         = "$prefix/lib/ruby/#{version}"
289   _siteruby        = "$prefix/lib/ruby/#{version}/site_ruby"
290   _siterubyver     = _siteruby
291   _siterubyverarch = "$siterubyver/#{c['arch']}"
292 end
293 libdir = '-* dummy libdir *-'
294 stdruby = '-* dummy rubylibdir *-'
295 siteruby = '-* dummy site_ruby *-'
296 siterubyver = '-* dummy site_ruby version *-'
297 parameterize = lambda {|path|
298   path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
299       .sub(/\A#{Regexp.quote(libdir)}/,      '$libdir')\
300       .sub(/\A#{Regexp.quote(stdruby)}/,     '$stdruby')\
301       .sub(/\A#{Regexp.quote(siteruby)}/,    '$siteruby')\
302       .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
303 }
304 libdir          = parameterize.call(c['libdir'])
305 stdruby         = parameterize.call(_stdruby)
306 siteruby        = parameterize.call(_siteruby)
307 siterubyver     = parameterize.call(_siterubyver)
308 siterubyverarch = parameterize.call(_siterubyverarch)
309
310 if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
311   makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
312 else
313   makeprog = 'make'
314 end
315
316 common_conf = [
317   PathItem.new('prefix', 'path', c['prefix'],
318                'path prefix of target environment'),
319   PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
320                'the directory for commands'),
321   PathItem.new('libdir', 'path', libdir,
322                'the directory for libraries'),
323   PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
324                'the directory for shared data'),
325   PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
326                'the directory for man pages'),
327   PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
328                'the directory for man pages'),
329   PathItem.new('stdruby', 'path', stdruby,
330                'the directory for standard ruby libraries'),
331   PathItem.new('siteruby', 'path', siteruby,
332       'the directory for version-independent aux ruby libraries'),
333   PathItem.new('siterubyver', 'path', siterubyver,
334                'the directory for aux ruby libraries'),
335   PathItem.new('siterubyverarch', 'path', siterubyverarch,
336                'the directory for aux ruby binaries'),
337   PathItem.new('rbdir', 'path', '$siterubyver',
338                'the directory for ruby scripts'),
339   PathItem.new('sodir', 'path', '$siterubyverarch',
340                'the directory for ruby extentions'),
341   PathItem.new('rubypath', 'path', rubypath,
342                'the path to set to #! line'),
343   ProgramItem.new('rubyprog', 'name', rubypath,
344                   'the ruby program using for installation'),
345   ProgramItem.new('makeprog', 'name', makeprog,
346                   'the make program to compile ruby extentions'),
347   SelectItem.new('shebang', 'all/ruby/never', 'ruby',
348                  'shebang line (#!) editing mode'),
349   BoolItem.new('without-ext', 'yes/no', 'no',
350                'does not compile/install ruby extentions')
351 ]
352 class ConfigTable_class   # open again
353   ALIASES = {
354     'std-ruby'         => 'stdruby',
355     'site-ruby-common' => 'siteruby',     # For backward compatibility
356     'site-ruby'        => 'siterubyver',  # For backward compatibility
357     'bin-dir'          => 'bindir',
358     'bin-dir'          => 'bindir',
359     'rb-dir'           => 'rbdir',
360     'so-dir'           => 'sodir',
361     'data-dir'         => 'datadir',
362     'ruby-path'        => 'rubypath',
363     'ruby-prog'        => 'rubyprog',
364     'ruby'             => 'rubyprog',
365     'make-prog'        => 'makeprog',
366     'make'             => 'makeprog'
367   }
368 end
369 multipackage_conf = [
370   PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
371                            'package names that you want to install'),
372   PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
373                            'package names that you do not want to install')
374 ]
375 if multipackage_install?
376   ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
377 else
378   ConfigTable = ConfigTable_class.new(common_conf)
379 end
380
381
382 module MetaConfigAPI
383
384   def eval_file_ifexist(fname)
385     instance_eval File.read(fname), fname, 1 if File.file?(fname)
386   end
387
388   def config_names
389     ConfigTable.map {|i| i.name }
390   end
391
392   def config?(name)
393     ConfigTable.key?(name)
394   end
395
396   def bool_config?(name)
397     ConfigTable.lookup(name).config_type == 'bool'
398   end
399
400   def path_config?(name)
401     ConfigTable.lookup(name).config_type == 'path'
402   end
403
404   def value_config?(name)
405     case ConfigTable.lookup(name).config_type
406     when 'bool', 'path'
407       true
408     else
409       false
410     end
411   end
412
413   def add_config(item)
414     ConfigTable.add item
415   end
416
417   def add_bool_config(name, default, desc)
418     ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
419   end
420
421   def add_path_config(name, default, desc)
422     ConfigTable.add PathItem.new(name, 'path', default, desc)
423   end
424
425   def set_config_default(name, default)
426     ConfigTable.lookup(name).default = default
427   end
428
429   def remove_config(name)
430     ConfigTable.remove(name)
431   end
432
433 end
434
435
436 #
437 # File Operations
438 #
439
440 module FileOperations
441
442   def mkdir_p(dirname, prefix = nil)
443     dirname = prefix + File.expand_path(dirname) if prefix
444     $stderr.puts "mkdir -p #{dirname}" if verbose?
445     return if no_harm?
446
447     # does not check '/'... it's too abnormal case
448     dirs = File.expand_path(dirname).split(%r<(?=/)>)
449     if /\A[a-z]:\z/i =~ dirs[0]
450       disk = dirs.shift
451       dirs[0] = disk + dirs[0]
452     end
453     dirs.each_index do |idx|
454       path = dirs[0..idx].join('')
455       Dir.mkdir path unless File.dir?(path)
456     end
457   end
458
459   def rm_f(fname)
460     $stderr.puts "rm -f #{fname}" if verbose?
461     return if no_harm?
462
463     if File.exist?(fname) or File.symlink?(fname)
464       File.chmod 0777, fname
465       File.unlink fname
466     end
467   end
468
469   def rm_rf(dn)
470     $stderr.puts "rm -rf #{dn}" if verbose?
471     return if no_harm?
472
473     Dir.chdir dn
474     Dir.foreach('.') do |fn|
475       next if fn == '.'
476       next if fn == '..'
477       if File.dir?(fn)
478         verbose_off {
479           rm_rf fn
480         }
481       else
482         verbose_off {
483           rm_f fn
484         }
485       end
486     end
487     Dir.chdir '..'
488     Dir.rmdir dn
489   end
490
491   def move_file(src, dest)
492     File.unlink dest if File.exist?(dest)
493     begin
494       File.rename src, dest
495     rescue
496       File.open(dest, 'wb') {|f| f.write File.binread(src) }
497       File.chmod File.stat(src).mode, dest
498       File.unlink src
499     end
500   end
501
502   def install(from, dest, mode, prefix = nil)
503     $stderr.puts "install #{from} #{dest}" if verbose?
504     return if no_harm?
505
506     realdest = prefix ? prefix + File.expand_path(dest) : dest
507     realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
508     str = File.binread(from)
509     if diff?(str, realdest)
510       verbose_off {
511         rm_f realdest if File.exist?(realdest)
512       }
513       File.open(realdest, 'wb') {|f|
514         f.write str
515       }
516       File.chmod mode, realdest
517
518       File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
519         if prefix
520           f.puts realdest.sub(prefix, '')
521         else
522           f.puts realdest
523         end
524       }
525     end
526   end
527
528   def diff?(new_content, path)
529     return true unless File.exist?(path)
530     new_content != File.binread(path)
531   end
532
533   def command(str)
534     $stderr.puts str if verbose?
535     system str or raise RuntimeError, "'system #{str}' failed"
536   end
537
538   def ruby(str)
539     command config('rubyprog') + ' ' + str
540   end
541  
542   def make(task = '')
543     command config('makeprog') + ' ' + task
544   end
545
546   def extdir?(dir)
547     File.exist?(dir + '/MANIFEST')
548   end
549
550   def all_files_in(dirname)
551     Dir.open(dirname) {|d|
552       return d.select {|ent| File.file?("#{dirname}/#{ent}") }
553     }
554   end
555
556   REJECT_DIRS = %w(
557     CVS SCCS RCS CVS.adm .svn
558   )
559
560   def all_dirs_in(dirname)
561     Dir.open(dirname) {|d|
562       return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
563     }
564   end
565
566 end
567
568
569 #
570 # Main Installer
571 #
572
573 module HookUtils
574
575   def run_hook(name)
576     try_run_hook "#{curr_srcdir()}/#{name}" or
577     try_run_hook "#{curr_srcdir()}/#{name}.rb"
578   end
579
580   def try_run_hook(fname)
581     return false unless File.file?(fname)
582     begin
583       instance_eval File.read(fname), fname, 1
584     rescue
585       setup_rb_error "hook #{fname} failed:\n" + $!.message
586     end
587     true
588   end
589
590 end
591
592
593 module HookScriptAPI
594
595<