root/version_0/setup.rb

Revision 54, 35.3 kB (checked in by blackhedd, 3 years ago)

Initial import

  • Property svn:keywords set to Id
Line 
1 #
2 # setup.rb
3 #
4 # Copyright (c) 2000-2005 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 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
33 def File.binread(fname)
34   open(fname, 'rb') {|f|
35     return f.read
36   }
37 end
38
39 # for corrupted Windows' stat(2)
40 def File.dir?(path)
41   File.directory?((path[-1,1] == '/') ? path : path + '/')
42 end
43
44
45 class ConfigTable
46
47   include Enumerable
48
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
58   end
59
60   attr_accessor :install_prefix
61   attr_accessor :config_opt
62
63   attr_writer :verbose
64
65   def verbose?
66     @verbose
67   end
68
69   attr_writer :no_harm
70
71   def no_harm?
72     @no_harm
73   end
74
75   def [](key)
76     lookup(key).resolve(self)
77   end
78
79   def []=(key, val)
80     lookup(key).set val
81   end
82
83   def names
84     @items.map {|i| i.name }
85   end
86
87   def each(&block)
88     @items.each(&block)
89   end
90
91   def key?(name)
92     @table.key?(name)
93   end
94
95   def lookup(name)
96     @table[name] or setup_rb_error "no such config item: #{name}"
97   end
98
99   def add(item)
100     @items.push item
101     @table[item.name] = item
102   end
103
104   def remove(name)
105     item = lookup(name)
106     @items.delete_if {|i| i.name == name }
107     @table.delete_if {|name, i| i.name == name }
108     item
109   end
110
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
115   end
116
117   def savefile
118     '.config'
119   end
120
121   def load_savefile
122     begin
123       File.foreach(savefile()) do |line|
124         k, v = *line.split(/=/, 2)
125         self[k] = v.strip
126       end
127     rescue Errno::ENOENT
128       setup_rb_error $!.message + "\n#{File.basename($0)} config first"
129     end
130   end
131
132   def save
133     @items.each {|i| i.value }
134     File.open(savefile(), 'w') {|f|
135       @items.each do |i|
136         f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
137       end
138     }
139   end
140
141   def load_standard_entries
142     standard_entries(@rbconfig).each do |ent|
143       add ent
144     end
145   end
146
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     }
191
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
197
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
275
276   ALIASES = {
277     'std-ruby'         => 'librubyver',
278     'stdruby'          => 'librubyver',
279     'rubylibdir'       => 'librubyver',
280     'archdir'          => 'librubyverarch',
281     'site-ruby-common' => 'siteruby',     # For backward compatibility
282     'site-ruby'        => 'siterubyver',  # For backward compatibility
283     'bin-dir'          => 'bindir',
284     'bin-dir'          => 'bindir',
285     'rb-dir'           => 'rbdir',
286     'so-dir'           => 'sodir',
287     'data-dir'         => 'datadir',
288     'ruby-path'        => 'rubypath',
289     'ruby-prog'        => 'rubyprog',
290     'ruby'             => 'rubyprog',
291     'make-prog'        => 'makeprog',
292     'make'             => 'makeprog'
293   }
294
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/
302   end
303
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]
307   end
308
309   def dllext
310     @rbconfig['DLEXT']
311   end
312
313   def value_config?(name)
314     lookup(name).value?
315   end
316
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
325
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?
337       true
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
357     end
358   end
359
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
380   end
381
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
393   end
394
395   class ProgramItem < Item
396     def config_type
397       'program'
398     end
399   end
400
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
419   end
420
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
449   end
450
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
456
457     attr_reader :help_default
458
459     def config_type
460       'package'
461     end
462
463     private
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?
536 module FileOperations
537
538   def mkdir_p(dirname, prefix = nil)
539     dirname = prefix + File.expand_path(dirname) if prefix
540     $stderr.puts "mkdir -p #{dirname}" if verbose?
541     return if no_harm?
542
543     # Does not check '/', it's too abnormal.
544     dirs = File.expand_path(dirname).split(%r<(?=/)>)
545     if /\A[a-z]:\z/i =~ dirs[0]
546       disk = dirs.shift
547       dirs[0] = disk + dirs[0]
548     end
549     dirs.each_index do |idx|
550       path = dirs[0..idx].join('')
551       Dir.mkdir path unless File.dir?(path)
552     end
553   end
554
555   def rm_f(path)
556     $stderr.puts "rm -f #{path}" if verbose?
557     return if no_harm?
558     force_remove_file path
559   end
560
561   def rm_rf(path)
562     $stderr.puts "rm -rf #{path}" if verbose?
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
576
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
586       else
587         force_remove_file entpath
588       end
589     end
590     begin
591       Dir.rmdir path
592     rescue Errno::ENOTEMPTY
593       # directory may not be empty
594     end
595   end
596