root / setup.rb

Revision 69, 35.3 kB (checked in by Brendan Taylor <whateley@…>, 2 years ago)

[project @ whateley@gmail.com-20061109181231-30abaf60cbef7ab5]
now with real installer!

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
11unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
12  module Enumerable
13    alias map collect
14  end
15end
16
17unless File.respond_to?(:read)   # Ruby 1.6
18  def File.read(fname)
19    open(fname) {|f|
20      return f.read
21    }
22  end
23end
24
25unless 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
31end
32
33def File.binread(fname)
34  open(fname, 'rb') {|f|
35    return f.read
36  }
37end
38
39# for corrupted Windows' stat(2)
40def File.dir?(path)
41  File.directory?((path[-1,1] == '/') ? path : path + '/')
42end
43
44
45class 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