annotate vendor/gems/rubytree-0.5.2/setup.rb @ 1452:d6b9fd02bb89 feature_36_js_refactoring

Deprecated develoment branch.
author luisf <luis.figueira@eecs.qmul.ac.uk>
date Fri, 11 Oct 2013 17:01:24 +0100
parents 513646585e45
children
rev   line source
Chris@0 1 #
Chris@0 2 # setup.rb
Chris@0 3 #
Chris@0 4 # Copyright (c) 2000-2005 Minero Aoki
Chris@0 5 #
Chris@0 6 # This program is free software.
Chris@0 7 # You can distribute/modify this program under the terms of
Chris@0 8 # the GNU LGPL, Lesser General Public License version 2.1.
Chris@0 9 #
Chris@0 10
Chris@0 11 unless Enumerable.method_defined?(:map) # Ruby 1.4.6
Chris@0 12 module Enumerable
Chris@0 13 alias map collect
Chris@0 14 end
Chris@0 15 end
Chris@0 16
Chris@0 17 unless File.respond_to?(:read) # Ruby 1.6
Chris@0 18 def File.read(fname)
Chris@0 19 open(fname) {|f|
Chris@0 20 return f.read
Chris@0 21 }
Chris@0 22 end
Chris@0 23 end
Chris@0 24
Chris@0 25 unless Errno.const_defined?(:ENOTEMPTY) # Windows?
Chris@0 26 module Errno
Chris@0 27 class ENOTEMPTY
Chris@0 28 # We do not raise this exception, implementation is not needed.
Chris@0 29 end
Chris@0 30 end
Chris@0 31 end
Chris@0 32
Chris@0 33 def File.binread(fname)
Chris@0 34 open(fname, 'rb') {|f|
Chris@0 35 return f.read
Chris@0 36 }
Chris@0 37 end
Chris@0 38
Chris@0 39 # for corrupted Windows' stat(2)
Chris@0 40 def File.dir?(path)
Chris@0 41 File.directory?((path[-1,1] == '/') ? path : path + '/')
Chris@0 42 end
Chris@0 43
Chris@0 44
Chris@0 45 class ConfigTable
Chris@0 46
Chris@0 47 include Enumerable
Chris@0 48
Chris@0 49 def initialize(rbconfig)
Chris@0 50 @rbconfig = rbconfig
Chris@0 51 @items = []
Chris@0 52 @table = {}
Chris@0 53 # options
Chris@0 54 @install_prefix = nil
Chris@0 55 @config_opt = nil
Chris@0 56 @verbose = true
Chris@0 57 @no_harm = false
Chris@0 58 end
Chris@0 59
Chris@0 60 attr_accessor :install_prefix
Chris@0 61 attr_accessor :config_opt
Chris@0 62
Chris@0 63 attr_writer :verbose
Chris@0 64
Chris@0 65 def verbose?
Chris@0 66 @verbose
Chris@0 67 end
Chris@0 68
Chris@0 69 attr_writer :no_harm
Chris@0 70
Chris@0 71 def no_harm?
Chris@0 72 @no_harm
Chris@0 73 end
Chris@0 74
Chris@0 75 def [](key)
Chris@0 76 lookup(key).resolve(self)
Chris@0 77 end
Chris@0 78
Chris@0 79 def []=(key, val)
Chris@0 80 lookup(key).set val
Chris@0 81 end
Chris@0 82
Chris@0 83 def names
Chris@0 84 @items.map {|i| i.name }
Chris@0 85 end
Chris@0 86
Chris@0 87 def each(&block)
Chris@0 88 @items.each(&block)
Chris@0 89 end
Chris@0 90
Chris@0 91 def key?(name)
Chris@0 92 @table.key?(name)
Chris@0 93 end
Chris@0 94
Chris@0 95 def lookup(name)
Chris@0 96 @table[name] or setup_rb_error "no such config item: #{name}"
Chris@0 97 end
Chris@0 98
Chris@0 99 def add(item)
Chris@0 100 @items.push item
Chris@0 101 @table[item.name] = item
Chris@0 102 end
Chris@0 103
Chris@0 104 def remove(name)
Chris@0 105 item = lookup(name)
Chris@0 106 @items.delete_if {|i| i.name == name }
Chris@0 107 @table.delete_if {|name, i| i.name == name }
Chris@0 108 item
Chris@0 109 end
Chris@0 110
Chris@0 111 def load_script(path, inst = nil)
Chris@0 112 if File.file?(path)
Chris@0 113 MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
Chris@0 114 end
Chris@0 115 end
Chris@0 116
Chris@0 117 def savefile
Chris@0 118 '.config'
Chris@0 119 end
Chris@0 120
Chris@0 121 def load_savefile
Chris@0 122 begin
Chris@0 123 File.foreach(savefile()) do |line|
Chris@0 124 k, v = *line.split(/=/, 2)
Chris@0 125 self[k] = v.strip
Chris@0 126 end
Chris@0 127 rescue Errno::ENOENT
Chris@0 128 setup_rb_error $!.message + "\n#{File.basename($0)} config first"
Chris@0 129 end
Chris@0 130 end
Chris@0 131
Chris@0 132 def save
Chris@0 133 @items.each {|i| i.value }
Chris@0 134 File.open(savefile(), 'w') {|f|
Chris@0 135 @items.each do |i|
Chris@0 136 f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
Chris@0 137 end
Chris@0 138 }
Chris@0 139 end
Chris@0 140
Chris@0 141 def load_standard_entries
Chris@0 142 standard_entries(@rbconfig).each do |ent|
Chris@0 143 add ent
Chris@0 144 end
Chris@0 145 end
Chris@0 146
Chris@0 147 def standard_entries(rbconfig)
Chris@0 148 c = rbconfig
Chris@0 149
Chris@0 150 rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
Chris@0 151
Chris@0 152 major = c['MAJOR'].to_i
Chris@0 153 minor = c['MINOR'].to_i
Chris@0 154 teeny = c['TEENY'].to_i
Chris@0 155 version = "#{major}.#{minor}"
Chris@0 156
Chris@0 157 # ruby ver. >= 1.4.4?
Chris@0 158 newpath_p = ((major >= 2) or
Chris@0 159 ((major == 1) and
Chris@0 160 ((minor >= 5) or
Chris@0 161 ((minor == 4) and (teeny >= 4)))))
Chris@0 162
Chris@0 163 if c['rubylibdir']
Chris@0 164 # V > 1.6.3
Chris@0 165 libruby = "#{c['prefix']}/lib/ruby"
Chris@0 166 librubyver = c['rubylibdir']
Chris@0 167 librubyverarch = c['archdir']
Chris@0 168 siteruby = c['sitedir']
Chris@0 169 siterubyver = c['sitelibdir']
Chris@0 170 siterubyverarch = c['sitearchdir']
Chris@0 171 elsif newpath_p
Chris@0 172 # 1.4.4 <= V <= 1.6.3
Chris@0 173 libruby = "#{c['prefix']}/lib/ruby"
Chris@0 174 librubyver = "#{c['prefix']}/lib/ruby/#{version}"
Chris@0 175 librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
Chris@0 176 siteruby = c['sitedir']
Chris@0 177 siterubyver = "$siteruby/#{version}"
Chris@0 178 siterubyverarch = "$siterubyver/#{c['arch']}"
Chris@0 179 else
Chris@0 180 # V < 1.4.4
Chris@0 181 libruby = "#{c['prefix']}/lib/ruby"
Chris@0 182 librubyver = "#{c['prefix']}/lib/ruby/#{version}"
Chris@0 183 librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
Chris@0 184 siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
Chris@0 185 siterubyver = siteruby
Chris@0 186 siterubyverarch = "$siterubyver/#{c['arch']}"
Chris@0 187 end
Chris@0 188 parameterize = lambda {|path|
Chris@0 189 path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
Chris@0 190 }
Chris@0 191
Chris@0 192 if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
Chris@0 193 makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
Chris@0 194 else
Chris@0 195 makeprog = 'make'
Chris@0 196 end
Chris@0 197
Chris@0 198 [
Chris@0 199 ExecItem.new('installdirs', 'std/site/home',
Chris@0 200 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
Chris@0 201 {|val, table|
Chris@0 202 case val
Chris@0 203 when 'std'
Chris@0 204 table['rbdir'] = '$librubyver'
Chris@0 205 table['sodir'] = '$librubyverarch'
Chris@0 206 when 'site'
Chris@0 207 table['rbdir'] = '$siterubyver'
Chris@0 208 table['sodir'] = '$siterubyverarch'
Chris@0 209 when 'home'
Chris@0 210 setup_rb_error '$HOME was not set' unless ENV['HOME']
Chris@0 211 table['prefix'] = ENV['HOME']
Chris@0 212 table['rbdir'] = '$libdir/ruby'
Chris@0 213 table['sodir'] = '$libdir/ruby'
Chris@0 214 end
Chris@0 215 },
Chris@0 216 PathItem.new('prefix', 'path', c['prefix'],
Chris@0 217 'path prefix of target environment'),
Chris@0 218 PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
Chris@0 219 'the directory for commands'),
Chris@0 220 PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
Chris@0 221 'the directory for libraries'),
Chris@0 222 PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
Chris@0 223 'the directory for shared data'),
Chris@0 224 PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
Chris@0 225 'the directory for man pages'),
Chris@0 226 PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
Chris@0 227 'the directory for system configuration files'),
Chris@0 228 PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
Chris@0 229 'the directory for local state data'),
Chris@0 230 PathItem.new('libruby', 'path', libruby,
Chris@0 231 'the directory for ruby libraries'),
Chris@0 232 PathItem.new('librubyver', 'path', librubyver,
Chris@0 233 'the directory for standard ruby libraries'),
Chris@0 234 PathItem.new('librubyverarch', 'path', librubyverarch,
Chris@0 235 'the directory for standard ruby extensions'),
Chris@0 236 PathItem.new('siteruby', 'path', siteruby,
Chris@0 237 'the directory for version-independent aux ruby libraries'),
Chris@0 238 PathItem.new('siterubyver', 'path', siterubyver,
Chris@0 239 'the directory for aux ruby libraries'),
Chris@0 240 PathItem.new('siterubyverarch', 'path', siterubyverarch,
Chris@0 241 'the directory for aux ruby binaries'),
Chris@0 242 PathItem.new('rbdir', 'path', '$siterubyver',
Chris@0 243 'the directory for ruby scripts'),
Chris@0 244 PathItem.new('sodir', 'path', '$siterubyverarch',
Chris@0 245 'the directory for ruby extentions'),
Chris@0 246 PathItem.new('rubypath', 'path', rubypath,
Chris@0 247 'the path to set to #! line'),
Chris@0 248 ProgramItem.new('rubyprog', 'name', rubypath,
Chris@0 249 'the ruby program using for installation'),
Chris@0 250 ProgramItem.new('makeprog', 'name', makeprog,
Chris@0 251 'the make program to compile ruby extentions'),
Chris@0 252 SelectItem.new('shebang', 'all/ruby/never', 'ruby',
Chris@0 253 'shebang line (#!) editing mode'),
Chris@0 254 BoolItem.new('without-ext', 'yes/no', 'no',
Chris@0 255 'does not compile/install ruby extentions')
Chris@0 256 ]
Chris@0 257 end
Chris@0 258 private :standard_entries
Chris@0 259
Chris@0 260 def load_multipackage_entries
Chris@0 261 multipackage_entries().each do |ent|
Chris@0 262 add ent
Chris@0 263 end
Chris@0 264 end
Chris@0 265
Chris@0 266 def multipackage_entries
Chris@0 267 [
Chris@0 268 PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
Chris@0 269 'package names that you want to install'),
Chris@0 270 PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
Chris@0 271 'package names that you do not want to install')
Chris@0 272 ]
Chris@0 273 end
Chris@0 274 private :multipackage_entries
Chris@0 275
Chris@0 276 ALIASES = {
Chris@0 277 'std-ruby' => 'librubyver',
Chris@0 278 'stdruby' => 'librubyver',
Chris@0 279 'rubylibdir' => 'librubyver',
Chris@0 280 'archdir' => 'librubyverarch',
Chris@0 281 'site-ruby-common' => 'siteruby', # For backward compatibility
Chris@0 282 'site-ruby' => 'siterubyver', # For backward compatibility
Chris@0 283 'bin-dir' => 'bindir',
Chris@0 284 'bin-dir' => 'bindir',
Chris@0 285 'rb-dir' => 'rbdir',
Chris@0 286 'so-dir' => 'sodir',
Chris@0 287 'data-dir' => 'datadir',
Chris@0 288 'ruby-path' => 'rubypath',
Chris@0 289 'ruby-prog' => 'rubyprog',
Chris@0 290 'ruby' => 'rubyprog',
Chris@0 291 'make-prog' => 'makeprog',
Chris@0 292 'make' => 'makeprog'
Chris@0 293 }
Chris@0 294
Chris@0 295 def fixup
Chris@0 296 ALIASES.each do |ali, name|
Chris@0 297 @table[ali] = @table[name]
Chris@0 298 end
Chris@0 299 @items.freeze
Chris@0 300 @table.freeze
Chris@0 301 @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
Chris@0 302 end
Chris@0 303
Chris@0 304 def parse_opt(opt)
Chris@0 305 m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
Chris@0 306 m.to_a[1,2]
Chris@0 307 end
Chris@0 308
Chris@0 309 def dllext
Chris@0 310 @rbconfig['DLEXT']
Chris@0 311 end
Chris@0 312
Chris@0 313 def value_config?(name)
Chris@0 314 lookup(name).value?
Chris@0 315 end
Chris@0 316
Chris@0 317 class Item
Chris@0 318 def initialize(name, template, default, desc)
Chris@0 319 @name = name.freeze
Chris@0 320 @template = template
Chris@0 321 @value = default
Chris@0 322 @default = default
Chris@0 323 @description = desc
Chris@0 324 end
Chris@0 325
Chris@0 326 attr_reader :name
Chris@0 327 attr_reader :description
Chris@0 328
Chris@0 329 attr_accessor :default
Chris@0 330 alias help_default default
Chris@0 331
Chris@0 332 def help_opt
Chris@0 333 "--#{@name}=#{@template}"
Chris@0 334 end
Chris@0 335
Chris@0 336 def value?
Chris@0 337 true
Chris@0 338 end
Chris@0 339
Chris@0 340 def value
Chris@0 341 @value
Chris@0 342 end
Chris@0 343
Chris@0 344 def resolve(table)
Chris@0 345 @value.gsub(%r<\$([^/]+)>) { table[$1] }
Chris@0 346 end
Chris@0 347
Chris@0 348 def set(val)
Chris@0 349 @value = check(val)
Chris@0 350 end
Chris@0 351
Chris@0 352 private
Chris@0 353
Chris@0 354 def check(val)
Chris@0 355 setup_rb_error "config: --#{name} requires argument" unless val
Chris@0 356 val
Chris@0 357 end
Chris@0 358 end
Chris@0 359
Chris@0 360 class BoolItem < Item
Chris@0 361 def config_type
Chris@0 362 'bool'
Chris@0 363 end
Chris@0 364
Chris@0 365 def help_opt
Chris@0 366 "--#{@name}"
Chris@0 367 end
Chris@0 368
Chris@0 369 private
Chris@0 370
Chris@0 371 def check(val)
Chris@0 372 return 'yes' unless val
Chris@0 373 case val
Chris@0 374 when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
Chris@0 375 when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
Chris@0 376 else
Chris@0 377 setup_rb_error "config: --#{@name} accepts only yes/no for argument"
Chris@0 378 end
Chris@0 379 end
Chris@0 380 end
Chris@0 381
Chris@0 382 class PathItem < Item
Chris@0 383 def config_type
Chris@0 384 'path'
Chris@0 385 end
Chris@0 386
Chris@0 387 private
Chris@0 388
Chris@0 389 def check(path)
Chris@0 390 setup_rb_error "config: --#{@name} requires argument" unless path
Chris@0 391 path[0,1] == '$' ? path : File.expand_path(path)
Chris@0 392 end
Chris@0 393 end
Chris@0 394
Chris@0 395 class ProgramItem < Item
Chris@0 396 def config_type
Chris@0 397 'program'
Chris@0 398 end
Chris@0 399 end
Chris@0 400
Chris@0 401 class SelectItem < Item
Chris@0 402 def initialize(name, selection, default, desc)
Chris@0 403 super
Chris@0 404 @ok = selection.split('/')
Chris@0 405 end
Chris@0 406
Chris@0 407 def config_type
Chris@0 408 'select'
Chris@0 409 end
Chris@0 410
Chris@0 411 private
Chris@0 412
Chris@0 413 def check(val)
Chris@0 414 unless @ok.include?(val.strip)
Chris@0 415 setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
Chris@0 416 end
Chris@0 417 val.strip
Chris@0 418 end
Chris@0 419 end
Chris@0 420
Chris@0 421 class ExecItem < Item
Chris@0 422 def initialize(name, selection, desc, &block)
Chris@0 423 super name, selection, nil, desc
Chris@0 424 @ok = selection.split('/')
Chris@0 425 @action = block
Chris@0 426 end
Chris@0 427
Chris@0 428 def config_type
Chris@0 429 'exec'
Chris@0 430 end
Chris@0 431
Chris@0 432 def value?
Chris@0 433 false
Chris@0 434 end
Chris@0 435
Chris@0 436 def resolve(table)
Chris@0 437 setup_rb_error "$#{name()} wrongly used as option value"
Chris@0 438 end
Chris@0 439
Chris@0 440 undef set
Chris@0 441
Chris@0 442 def evaluate(val, table)
Chris@0 443 v = val.strip.downcase
Chris@0 444 unless @ok.include?(v)
Chris@0 445 setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
Chris@0 446 end
Chris@0 447 @action.call v, table
Chris@0 448 end
Chris@0 449 end
Chris@0 450
Chris@0 451 class PackageSelectionItem < Item
Chris@0 452 def initialize(name, template, default, help_default, desc)
Chris@0 453 super name, template, default, desc
Chris@0 454 @help_default = help_default
Chris@0 455 end
Chris@0 456
Chris@0 457 attr_reader :help_default
Chris@0 458
Chris@0 459 def config_type
Chris@0 460 'package'
Chris@0 461 end
Chris@0 462
Chris@0 463 private
Chris@0 464
Chris@0 465 def check(val)
Chris@0 466 unless File.dir?("packages/#{val}")
Chris@0 467 setup_rb_error "config: no such package: #{val}"
Chris@0 468 end
Chris@0 469 val
Chris@0 470 end
Chris@0 471 end
Chris@0 472
Chris@0 473 class MetaConfigEnvironment
Chris@0 474 def initialize(config, installer)
Chris@0 475 @config = config
Chris@0 476 @installer = installer
Chris@0 477 end
Chris@0 478
Chris@0 479 def config_names
Chris@0 480 @config.names
Chris@0 481 end
Chris@0 482
Chris@0 483 def config?(name)
Chris@0 484 @config.key?(name)
Chris@0 485 end
Chris@0 486
Chris@0 487 def bool_config?(name)
Chris@0 488 @config.lookup(name).config_type == 'bool'
Chris@0 489 end
Chris@0 490
Chris@0 491 def path_config?(name)
Chris@0 492 @config.lookup(name).config_type == 'path'
Chris@0 493 end
Chris@0 494
Chris@0 495 def value_config?(name)
Chris@0 496 @config.lookup(name).config_type != 'exec'
Chris@0 497 end
Chris@0 498
Chris@0 499 def add_config(item)
Chris@0 500 @config.add item
Chris@0 501 end
Chris@0 502
Chris@0 503 def add_bool_config(name, default, desc)
Chris@0 504 @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
Chris@0 505 end
Chris@0 506
Chris@0 507 def add_path_config(name, default, desc)
Chris@0 508 @config.add PathItem.new(name, 'path', default, desc)
Chris@0 509 end
Chris@0 510
Chris@0 511 def set_config_default(name, default)
Chris@0 512 @config.lookup(name).default = default
Chris@0 513 end
Chris@0 514
Chris@0 515 def remove_config(name)
Chris@0 516 @config.remove(name)
Chris@0 517 end
Chris@0 518
Chris@0 519 # For only multipackage
Chris@0 520 def packages
Chris@0 521 raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
Chris@0 522 @installer.packages
Chris@0 523 end
Chris@0 524
Chris@0 525 # For only multipackage
Chris@0 526 def declare_packages(list)
Chris@0 527 raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
Chris@0 528 @installer.packages = list
Chris@0 529 end
Chris@0 530 end
Chris@0 531
Chris@0 532 end # class ConfigTable
Chris@0 533
Chris@0 534
Chris@0 535 # This module requires: #verbose?, #no_harm?
Chris@0 536 module FileOperations
Chris@0 537
Chris@0 538 def mkdir_p(dirname, prefix = nil)
Chris@0 539 dirname = prefix + File.expand_path(dirname) if prefix
Chris@0 540 $stderr.puts "mkdir -p #{dirname}" if verbose?
Chris@0 541 return if no_harm?
Chris@0 542
Chris@0 543 # Does not check '/', it's too abnormal.
Chris@0 544 dirs = File.expand_path(dirname).split(%r<(?=/)>)
Chris@0 545 if /\A[a-z]:\z/i =~ dirs[0]
Chris@0 546 disk = dirs.shift
Chris@0 547 dirs[0] = disk + dirs[0]
Chris@0 548 end
Chris@0 549 dirs.each_index do |idx|
Chris@0 550 path = dirs[0..idx].join('')
Chris@0 551 Dir.mkdir path unless File.dir?(path)
Chris@0 552 end
Chris@0 553 end
Chris@0 554
Chris@0 555 def rm_f(path)
Chris@0 556 $stderr.puts "rm -f #{path}" if verbose?
Chris@0 557 return if no_harm?
Chris@0 558 force_remove_file path
Chris@0 559 end
Chris@0 560
Chris@0 561 def rm_rf(path)
Chris@0 562 $stderr.puts "rm -rf #{path}" if verbose?
Chris@0 563 return if no_harm?
Chris@0 564 remove_tree path
Chris@0 565 end
Chris@0 566
Chris@0 567 def remove_tree(path)
Chris@0 568 if File.symlink?(path)
Chris@0 569 remove_file path
Chris@0 570 elsif File.dir?(path)
Chris@0 571 remove_tree0 path
Chris@0 572 else
Chris@0 573 force_remove_file path
Chris@0 574 end
Chris@0 575 end
Chris@0 576
Chris@0 577 def remove_tree0(path)
Chris@0 578 Dir.foreach(path) do |ent|
Chris@0 579 next if ent == '.'
Chris@0 580 next if ent == '..'
Chris@0 581 entpath = "#{path}/#{ent}"
Chris@0 582 if File.symlink?(entpath)
Chris@0 583 remove_file entpath
Chris@0 584 elsif File.dir?(entpath)
Chris@0 585 remove_tree0 entpath
Chris@0 586 else
Chris@0 587 force_remove_file entpath
Chris@0 588 end
Chris@0 589 end
Chris@0 590 begin
Chris@0 591 Dir.rmdir path
Chris@0 592 rescue Errno::ENOTEMPTY
Chris@0 593 # directory may not be empty
Chris@0 594 end
Chris@0 595 end
Chris@0 596
Chris@0 597 def move_file(src, dest)
Chris@0 598 force_remove_file dest
Chris@0 599 begin
Chris@0 600 File.rename src, dest
Chris@0 601 rescue
Chris@0 602 File.open(dest, 'wb') {|f|
Chris@0 603 f.write File.binread(src)
Chris@0 604 }
Chris@0 605 File.chmod File.stat(src).mode, dest
Chris@0 606 File.unlink src
Chris@0 607 end
Chris@0 608 end
Chris@0 609
Chris@0 610 def force_remove_file(path)
Chris@0 611 begin
Chris@0 612 remove_file path
Chris@0 613 rescue
Chris@0 614 end
Chris@0 615 end
Chris@0 616
Chris@0 617 def remove_file(path)
Chris@0 618 File.chmod 0777, path
Chris@0 619 File.unlink path
Chris@0 620 end
Chris@0 621
Chris@0 622 def install(from, dest, mode, prefix = nil)
Chris@0 623 $stderr.puts "install #{from} #{dest}" if verbose?
Chris@0 624 return if no_harm?
Chris@0 625
Chris@0 626 realdest = prefix ? prefix + File.expand_path(dest) : dest
Chris@0 627 realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
Chris@0 628 str = File.binread(from)
Chris@0 629 if diff?(str, realdest)
Chris@0 630 verbose_off {
Chris@0 631 rm_f realdest if File.exist?(realdest)
Chris@0 632 }
Chris@0 633 File.open(realdest, 'wb') {|f|
Chris@0 634 f.write str
Chris@0 635 }
Chris@0 636 File.chmod mode, realdest
Chris@0 637
Chris@0 638 File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
Chris@0 639 if prefix
Chris@0 640 f.puts realdest.sub(prefix, '')
Chris@0 641 else
Chris@0 642 f.puts realdest
Chris@0 643 end
Chris@0 644 }
Chris@0 645 end
Chris@0 646 end
Chris@0 647
Chris@0 648 def diff?(new_content, path)
Chris@0 649 return true unless File.exist?(path)
Chris@0 650 new_content != File.binread(path)
Chris@0 651 end
Chris@0 652
Chris@0 653 def command(*args)
Chris@0 654 $stderr.puts args.join(' ') if verbose?
Chris@0 655 system(*args) or raise RuntimeError,
Chris@0 656 "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
Chris@0 657 end
Chris@0 658
Chris@0 659 def ruby(*args)
Chris@0 660 command config('rubyprog'), *args
Chris@0 661 end
Chris@0 662
Chris@0 663 def make(task = nil)
Chris@0 664 command(*[config('makeprog'), task].compact)
Chris@0 665 end
Chris@0 666
Chris@0 667 def extdir?(dir)
Chris@0 668 File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
Chris@0 669 end
Chris@0 670
Chris@0 671 def files_of(dir)
Chris@0 672 Dir.open(dir) {|d|
Chris@0 673 return d.select {|ent| File.file?("#{dir}/#{ent}") }
Chris@0 674 }
Chris@0 675 end
Chris@0 676
Chris@0 677 DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
Chris@0 678
Chris@0 679 def directories_of(dir)
Chris@0 680 Dir.open(dir) {|d|
Chris@0 681 return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
Chris@0 682 }
Chris@0 683 end
Chris@0 684
Chris@0 685 end
Chris@0 686
Chris@0 687
Chris@0 688 # This module requires: #srcdir_root, #objdir_root, #relpath
Chris@0 689 module HookScriptAPI
Chris@0 690
Chris@0 691 def get_config(key)
Chris@0 692 @config[key]
Chris@0 693 end
Chris@0 694
Chris@0 695 alias config get_config
Chris@0 696
Chris@0 697 # obsolete: use metaconfig to change configuration
Chris@0 698 def set_config(key, val)
Chris@0 699 @config[key] = val
Chris@0 700 end
Chris@0 701
Chris@0 702 #
Chris@0 703 # srcdir/objdir (works only in the package directory)
Chris@0 704 #
Chris@0 705
Chris@0 706 def curr_srcdir
Chris@0 707 "#{srcdir_root()}/#{relpath()}"
Chris@0 708 end
Chris@0 709
Chris@0 710 def curr_objdir
Chris@0 711 "#{objdir_root()}/#{relpath()}"
Chris@0 712 end
Chris@0 713
Chris@0 714 def srcfile(path)
Chris@0 715 "#{curr_srcdir()}/#{path}"
Chris@0 716 end
Chris@0 717
Chris@0 718 def srcexist?(path)
Chris@0 719 File.exist?(srcfile(path))
Chris@0 720 end
Chris@0 721
Chris@0 722 def srcdirectory?(path)
Chris@0 723 File.dir?(srcfile(path))
Chris@0 724 end
Chris@0 725
Chris@0 726 def srcfile?(path)
Chris@0 727 File.file?(srcfile(path))
Chris@0 728 end
Chris@0 729
Chris@0 730 def srcentries(path = '.')
Chris@0 731 Dir.open("#{curr_srcdir()}/#{path}") {|d|
Chris@0 732 return d.to_a - %w(. ..)
Chris@0 733 }
Chris@0 734 end
Chris@0 735
Chris@0 736 def srcfiles(path = '.')
Chris@0 737 srcentries(path).select {|fname|
Chris@0 738 File.file?(File.join(curr_srcdir(), path, fname))
Chris@0 739 }
Chris@0 740 end
Chris@0 741
Chris@0 742 def srcdirectories(path = '.')
Chris@0 743 srcentries(path).select {|fname|
Chris@0 744 File.dir?(File.join(curr_srcdir(), path, fname))
Chris@0 745 }
Chris@0 746 end
Chris@0 747
Chris@0 748 end
Chris@0 749
Chris@0 750
Chris@0 751 class ToplevelInstaller
Chris@0 752
Chris@0 753 Version = '3.4.1'
Chris@0 754 Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
Chris@0 755
Chris@0 756 TASKS = [
Chris@0 757 [ 'all', 'do config, setup, then install' ],
Chris@0 758 [ 'config', 'saves your configurations' ],
Chris@0 759 [ 'show', 'shows current configuration' ],
Chris@0 760 [ 'setup', 'compiles ruby extentions and others' ],
Chris@0 761 [ 'install', 'installs files' ],
Chris@0 762 [ 'test', 'run all tests in test/' ],
Chris@0 763 [ 'clean', "does `make clean' for each extention" ],
Chris@0 764 [ 'distclean',"does `make distclean' for each extention" ]
Chris@0 765 ]
Chris@0 766
Chris@0 767 def ToplevelInstaller.invoke
Chris@0 768 config = ConfigTable.new(load_rbconfig())
Chris@0 769 config.load_standard_entries
Chris@0 770 config.load_multipackage_entries if multipackage?
Chris@0 771 config.fixup
Chris@0 772 klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
Chris@0 773 klass.new(File.dirname($0), config).invoke
Chris@0 774 end
Chris@0 775
Chris@0 776 def ToplevelInstaller.multipackage?
Chris@0 777 File.dir?(File.dirname($0) + '/packages')
Chris@0 778 end
Chris@0 779
Chris@0 780 def ToplevelInstaller.load_rbconfig
Chris@0 781 if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
Chris@0 782 ARGV.delete(arg)
Chris@0 783 load File.expand_path(arg.split(/=/, 2)[1])
Chris@0 784 $".push 'rbconfig.rb'
Chris@0 785 else
Chris@0 786 require 'rbconfig'
Chris@0 787 end
Chris@0 788 ::Config::CONFIG
Chris@0 789 end
Chris@0 790
Chris@0 791 def initialize(ardir_root, config)
Chris@0 792 @ardir = File.expand_path(ardir_root)
Chris@0 793 @config = config
Chris@0 794 # cache
Chris@0 795 @valid_task_re = nil
Chris@0 796 end
Chris@0 797
Chris@0 798 def config(key)
Chris@0 799 @config[key]
Chris@0 800 end
Chris@0 801
Chris@0 802 def inspect
Chris@0 803 "#<#{self.class} #{__id__()}>"
Chris@0 804 end
Chris@0 805
Chris@0 806 def invoke
Chris@0 807 run_metaconfigs
Chris@0 808 case task = parsearg_global()
Chris@0 809 when nil, 'all'
Chris@0 810 parsearg_config
Chris@0 811 init_installers
Chris@0 812 exec_config
Chris@0 813 exec_setup
Chris@0 814 exec_install
Chris@0 815 else
Chris@0 816 case task
Chris@0 817 when 'config', 'test'
Chris@0 818 ;
Chris@0 819 when 'clean', 'distclean'
Chris@0 820 @config.load_savefile if File.exist?(@config.savefile)
Chris@0 821 else
Chris@0 822 @config.load_savefile
Chris@0 823 end
Chris@0 824 __send__ "parsearg_#{task}"
Chris@0 825 init_installers
Chris@0 826 __send__ "exec_#{task}"
Chris@0 827 end
Chris@0 828 end
Chris@0 829
Chris@0 830 def run_metaconfigs
Chris@0 831 @config.load_script "#{@ardir}/metaconfig"
Chris@0 832 end
Chris@0 833
Chris@0 834 def init_installers
Chris@0 835 @installer = Installer.new(@config, @ardir, File.expand_path('.'))
Chris@0 836 end
Chris@0 837
Chris@0 838 #
Chris@0 839 # Hook Script API bases
Chris@0 840 #
Chris@0 841
Chris@0 842 def srcdir_root
Chris@0 843 @ardir
Chris@0 844 end
Chris@0 845
Chris@0 846 def objdir_root
Chris@0 847 '.'
Chris@0 848 end
Chris@0 849
Chris@0 850 def relpath
Chris@0 851 '.'
Chris@0 852 end
Chris@0 853
Chris@0 854 #
Chris@0 855 # Option Parsing
Chris@0 856 #
Chris@0 857
Chris@0 858 def parsearg_global
Chris@0 859 while arg = ARGV.shift
Chris@0 860 case arg
Chris@0 861 when /\A\w+\z/
Chris@0 862 setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
Chris@0 863 return arg
Chris@0 864 when '-q', '--quiet'
Chris@0 865 @config.verbose = false
Chris@0 866 when '--verbose'
Chris@0 867 @config.verbose = true
Chris@0 868 when '--help'
Chris@0 869 print_usage $stdout
Chris@0 870 exit 0
Chris@0 871 when '--version'
Chris@0 872 puts "#{File.basename($0)} version #{Version}"
Chris@0 873 exit 0
Chris@0 874 when '--copyright'
Chris@0 875 puts Copyright
Chris@0 876 exit 0
Chris@0 877 else
Chris@0 878 setup_rb_error "unknown global option '#{arg}'"
Chris@0 879 end
Chris@0 880 end
Chris@0 881 nil
Chris@0 882 end
Chris@0 883
Chris@0 884 def valid_task?(t)
Chris@0 885 valid_task_re() =~ t
Chris@0 886 end
Chris@0 887
Chris@0 888 def valid_task_re
Chris@0 889 @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
Chris@0 890 end
Chris@0 891
Chris@0 892 def parsearg_no_options
Chris@0 893 unless ARGV.empty?
Chris@0 894 task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
Chris@0 895 setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
Chris@0 896 end
Chris@0 897 end
Chris@0 898
Chris@0 899 alias parsearg_show parsearg_no_options
Chris@0 900 alias parsearg_setup parsearg_no_options
Chris@0 901 alias parsearg_test parsearg_no_options
Chris@0 902 alias parsearg_clean parsearg_no_options
Chris@0 903 alias parsearg_distclean parsearg_no_options
Chris@0 904
Chris@0 905 def parsearg_config
Chris@0 906 evalopt = []
Chris@0 907 set = []
Chris@0 908 @config.config_opt = []
Chris@0 909 while i = ARGV.shift
Chris@0 910 if /\A--?\z/ =~ i
Chris@0 911 @config.config_opt = ARGV.dup
Chris@0 912 break
Chris@0 913 end
Chris@0 914 name, value = *@config.parse_opt(i)
Chris@0 915 if @config.value_config?(name)
Chris@0 916 @config[name] = value
Chris@0 917 else
Chris@0 918 evalopt.push [name, value]
Chris@0 919 end
Chris@0 920 set.push name
Chris@0 921 end
Chris@0 922 evalopt.each do |name, value|
Chris@0 923 @config.lookup(name).evaluate value, @config
Chris@0 924 end
Chris@0 925 # Check if configuration is valid
Chris@0 926 set.each do |n|
Chris@0 927 @config[n] if @config.value_config?(n)
Chris@0 928 end
Chris@0 929 end
Chris@0 930
Chris@0 931 def parsearg_install
Chris@0 932 @config.no_harm = false
Chris@0 933 @config.install_prefix = ''
Chris@0 934 while a = ARGV.shift
Chris@0 935 case a
Chris@0 936 when '--no-harm'
Chris@0 937 @config.no_harm = true
Chris@0 938 when /\A--prefix=/
Chris@0 939 path = a.split(/=/, 2)[1]
Chris@0 940 path = File.expand_path(path) unless path[0,1] == '/'
Chris@0 941 @config.install_prefix = path
Chris@0 942 else
Chris@0 943 setup_rb_error "install: unknown option #{a}"
Chris@0 944 end
Chris@0 945 end
Chris@0 946 end
Chris@0 947
Chris@0 948 def print_usage(out)
Chris@0 949 out.puts 'Typical Installation Procedure:'
Chris@0 950 out.puts " $ ruby #{File.basename $0} config"
Chris@0 951 out.puts " $ ruby #{File.basename $0} setup"
Chris@0 952 out.puts " # ruby #{File.basename $0} install (may require root privilege)"
Chris@0 953 out.puts
Chris@0 954 out.puts 'Detailed Usage:'
Chris@0 955 out.puts " ruby #{File.basename $0} <global option>"
Chris@0 956 out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
Chris@0 957
Chris@0 958 fmt = " %-24s %s\n"
Chris@0 959 out.puts
Chris@0 960 out.puts 'Global options:'
Chris@0 961 out.printf fmt, '-q,--quiet', 'suppress message outputs'
Chris@0 962 out.printf fmt, ' --verbose', 'output messages verbosely'
Chris@0 963 out.printf fmt, ' --help', 'print this message'
Chris@0 964 out.printf fmt, ' --version', 'print version and quit'
Chris@0 965 out.printf fmt, ' --copyright', 'print copyright and quit'
Chris@0 966 out.puts
Chris@0 967 out.puts 'Tasks:'
Chris@0 968 TASKS.each do |name, desc|
Chris@0 969 out.printf fmt, name, desc
Chris@0 970 end
Chris@0 971
Chris@0 972 fmt = " %-24s %s [%s]\n"
Chris@0 973 out.puts
Chris@0 974 out.puts 'Options for CONFIG or ALL:'
Chris@0 975 @config.each do |item|
Chris@0 976 out.printf fmt, item.help_opt, item.description, item.help_default
Chris@0 977 end
Chris@0 978 out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
Chris@0 979 out.puts
Chris@0 980 out.puts 'Options for INSTALL:'
Chris@0 981 out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
Chris@0 982 out.printf fmt, '--prefix=path', 'install path prefix', ''
Chris@0 983 out.puts
Chris@0 984 end
Chris@0 985
Chris@0 986 #
Chris@0 987 # Task Handlers
Chris@0 988 #
Chris@0 989
Chris@0 990 def exec_config
Chris@0 991 @installer.exec_config
Chris@0 992 @config.save # must be final
Chris@0 993 end
Chris@0 994
Chris@0 995 def exec_setup
Chris@0 996 @installer.exec_setup
Chris@0 997 end
Chris@0 998
Chris@0 999 def exec_install
Chris@0 1000 @installer.exec_install
Chris@0 1001 end
Chris@0 1002
Chris@0 1003 def exec_test
Chris@0 1004 @installer.exec_test
Chris@0 1005 end
Chris@0 1006
Chris@0 1007 def exec_show
Chris@0 1008 @config.each do |i|
Chris@0 1009 printf "%-20s %s\n", i.name, i.value if i.value?
Chris@0 1010 end
Chris@0 1011 end
Chris@0 1012
Chris@0 1013 def exec_clean
Chris@0 1014 @installer.exec_clean
Chris@0 1015 end
Chris@0 1016
Chris@0 1017 def exec_distclean
Chris@0 1018 @installer.exec_distclean
Chris@0 1019 end
Chris@0 1020
Chris@0 1021 end # class ToplevelInstaller
Chris@0 1022
Chris@0 1023
Chris@0 1024 class ToplevelInstallerMulti < ToplevelInstaller
Chris@0 1025
Chris@0 1026 include FileOperations
Chris@0 1027
Chris@0 1028 def initialize(ardir_root, config)
Chris@0 1029 super
Chris@0 1030 @packages = directories_of("#{@ardir}/packages")
Chris@0 1031 raise 'no package exists' if @packages.empty?
Chris@0 1032 @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
Chris@0 1033 end
Chris@0 1034
Chris@0 1035 def run_metaconfigs
Chris@0 1036 @config.load_script "#{@ardir}/metaconfig", self
Chris@0 1037 @packages.each do |name|
Chris@0 1038 @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
Chris@0 1039 end
Chris@0 1040 end
Chris@0 1041
Chris@0 1042 attr_reader :packages
Chris@0 1043
Chris@0 1044 def packages=(list)
Chris@0 1045 raise 'package list is empty' if list.empty?
Chris@0 1046 list.each do |name|
Chris@0 1047 raise "directory packages/#{name} does not exist"\
Chris@0 1048 unless File.dir?("#{@ardir}/packages/#{name}")
Chris@0 1049 end
Chris@0 1050 @packages = list
Chris@0 1051 end
Chris@0 1052
Chris@0 1053 def init_installers
Chris@0 1054 @installers = {}
Chris@0 1055 @packages.each do |pack|
Chris@0 1056 @installers[pack] = Installer.new(@config,
Chris@0 1057 "#{@ardir}/packages/#{pack}",
Chris@0 1058 "packages/#{pack}")
Chris@0 1059 end
Chris@0 1060 with = extract_selection(config('with'))
Chris@0 1061 without = extract_selection(config('without'))
Chris@0 1062 @selected = @installers.keys.select {|name|
Chris@0 1063 (with.empty? or with.include?(name)) \
Chris@0 1064 and not without.include?(name)
Chris@0 1065 }
Chris@0 1066 end
Chris@0 1067
Chris@0 1068 def extract_selection(list)
Chris@0 1069 a = list.split(/,/)
Chris@0 1070 a.each do |name|
Chris@0 1071 setup_rb_error "no such package: #{name}" unless @installers.key?(name)
Chris@0 1072 end
Chris@0 1073 a
Chris@0 1074 end
Chris@0 1075
Chris@0 1076 def print_usage(f)
Chris@0 1077 super
Chris@0 1078 f.puts 'Inluded packages:'
Chris@0 1079 f.puts ' ' + @packages.sort.join(' ')
Chris@0 1080 f.puts
Chris@0 1081 end
Chris@0 1082
Chris@0 1083 #
Chris@0 1084 # Task Handlers
Chris@0 1085 #
Chris@0 1086
Chris@0 1087 def exec_config
Chris@0 1088 run_hook 'pre-config'
Chris@0 1089 each_selected_installers {|inst| inst.exec_config }
Chris@0 1090 run_hook 'post-config'
Chris@0 1091 @config.save # must be final
Chris@0 1092 end
Chris@0 1093
Chris@0 1094 def exec_setup
Chris@0 1095 run_hook 'pre-setup'
Chris@0 1096 each_selected_installers {|inst| inst.exec_setup }
Chris@0 1097 run_hook 'post-setup'
Chris@0 1098 end
Chris@0 1099
Chris@0 1100 def exec_install
Chris@0 1101 run_hook 'pre-install'
Chris@0 1102 each_selected_installers {|inst| inst.exec_install }
Chris@0 1103 run_hook 'post-install'
Chris@0 1104 end
Chris@0 1105
Chris@0 1106 def exec_test
Chris@0 1107 run_hook 'pre-test'
Chris@0 1108 each_selected_installers {|inst| inst.exec_test }
Chris@0 1109 run_hook 'post-test'
Chris@0 1110 end
Chris@0 1111
Chris@0 1112 def exec_clean
Chris@0 1113 rm_f @config.savefile
Chris@0 1114 run_hook 'pre-clean'
Chris@0 1115 each_selected_installers {|inst| inst.exec_clean }
Chris@0 1116 run_hook 'post-clean'
Chris@0 1117 end
Chris@0 1118
Chris@0 1119 def exec_distclean
Chris@0 1120 rm_f @config.savefile
Chris@0 1121 run_hook 'pre-distclean'
Chris@0 1122 each_selected_installers {|inst| inst.exec_distclean }
Chris@0 1123 run_hook 'post-distclean'
Chris@0 1124 end
Chris@0 1125
Chris@0 1126 #
Chris@0 1127 # lib
Chris@0 1128 #
Chris@0 1129
Chris@0 1130 def each_selected_installers
Chris@0 1131 Dir.mkdir 'packages' unless File.dir?('packages')
Chris@0 1132 @selected.each do |pack|
Chris@0 1133 $stderr.puts "Processing the package `#{pack}' ..." if verbose?
Chris@0 1134 Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
Chris@0 1135 Dir.chdir "packages/#{pack}"
Chris@0 1136 yield @installers[pack]
Chris@0 1137 Dir.chdir '../..'
Chris@0 1138 end
Chris@0 1139 end
Chris@0 1140
Chris@0 1141 def run_hook(id)
Chris@0 1142 @root_installer.run_hook id
Chris@0 1143 end
Chris@0 1144
Chris@0 1145 # module FileOperations requires this
Chris@0 1146 def verbose?
Chris@0 1147 @config.verbose?
Chris@0 1148 end
Chris@0 1149
Chris@0 1150 # module FileOperations requires this
Chris@0 1151 def no_harm?
Chris@0 1152 @config.no_harm?
Chris@0 1153 end
Chris@0 1154
Chris@0 1155 end # class ToplevelInstallerMulti
Chris@0 1156
Chris@0 1157
Chris@0 1158 class Installer
Chris@0 1159
Chris@0 1160 FILETYPES = %w( bin lib ext data conf man )
Chris@0 1161
Chris@0 1162 include FileOperations
Chris@0 1163 include HookScriptAPI
Chris@0 1164
Chris@0 1165 def initialize(config, srcroot, objroot)
Chris@0 1166 @config = config
Chris@0 1167 @srcdir = File.expand_path(srcroot)
Chris@0 1168 @objdir = File.expand_path(objroot)
Chris@0 1169 @currdir = '.'
Chris@0 1170 end
Chris@0 1171
Chris@0 1172 def inspect
Chris@0 1173 "#<#{self.class} #{File.basename(@srcdir)}>"
Chris@0 1174 end
Chris@0 1175
Chris@0 1176 def noop(rel)
Chris@0 1177 end
Chris@0 1178
Chris@0 1179 #
Chris@0 1180 # Hook Script API base methods
Chris@0 1181 #
Chris@0 1182
Chris@0 1183 def srcdir_root
Chris@0 1184 @srcdir
Chris@0 1185 end
Chris@0 1186
Chris@0 1187 def objdir_root
Chris@0 1188 @objdir
Chris@0 1189 end
Chris@0 1190
Chris@0 1191 def relpath
Chris@0 1192 @currdir
Chris@0 1193 end
Chris@0 1194
Chris@0 1195 #
Chris@0 1196 # Config Access
Chris@0 1197 #
Chris@0 1198
Chris@0 1199 # module FileOperations requires this
Chris@0 1200 def verbose?
Chris@0 1201 @config.verbose?
Chris@0 1202 end
Chris@0 1203
Chris@0 1204 # module FileOperations requires this
Chris@0 1205 def no_harm?
Chris@0 1206 @config.no_harm?
Chris@0 1207 end
Chris@0 1208
Chris@0 1209 def verbose_off
Chris@0 1210 begin
Chris@0 1211 save, @config.verbose = @config.verbose?, false
Chris@0 1212 yield
Chris@0 1213 ensure
Chris@0 1214 @config.verbose = save
Chris@0 1215 end
Chris@0 1216 end
Chris@0 1217
Chris@0 1218 #
Chris@0 1219 # TASK config
Chris@0 1220 #
Chris@0 1221
Chris@0 1222 def exec_config
Chris@0 1223 exec_task_traverse 'config'
Chris@0 1224 end
Chris@0 1225
Chris@0 1226 alias config_dir_bin noop
Chris@0 1227 alias config_dir_lib noop
Chris@0 1228
Chris@0 1229 def config_dir_ext(rel)
Chris@0 1230 extconf if extdir?(curr_srcdir())
Chris@0 1231 end
Chris@0 1232
Chris@0 1233 alias config_dir_data noop
Chris@0 1234 alias config_dir_conf noop
Chris@0 1235 alias config_dir_man noop
Chris@0 1236
Chris@0 1237 def extconf
Chris@0 1238 ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
Chris@0 1239 end
Chris@0 1240
Chris@0 1241 #
Chris@0 1242 # TASK setup
Chris@0 1243 #
Chris@0 1244
Chris@0 1245 def exec_setup
Chris@0 1246 exec_task_traverse 'setup'
Chris@0 1247 end
Chris@0 1248
Chris@0 1249 def setup_dir_bin(rel)
Chris@0 1250 files_of(curr_srcdir()).each do |fname|
Chris@0 1251 update_shebang_line "#{curr_srcdir()}/#{fname}"
Chris@0 1252 end
Chris@0 1253 end
Chris@0 1254
Chris@0 1255 alias setup_dir_lib noop
Chris@0 1256
Chris@0 1257 def setup_dir_ext(rel)
Chris@0 1258 make if extdir?(curr_srcdir())
Chris@0 1259 end
Chris@0 1260
Chris@0 1261 alias setup_dir_data noop
Chris@0 1262 alias setup_dir_conf noop
Chris@0 1263 alias setup_dir_man noop
Chris@0 1264
Chris@0 1265 def update_shebang_line(path)
Chris@0 1266 return if no_harm?
Chris@0 1267 return if config('shebang') == 'never'
Chris@0 1268 old = Shebang.load(path)
Chris@0 1269 if old
Chris@0 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
Chris@0 1271 new = new_shebang(old)
Chris@0 1272 return if new.to_s == old.to_s
Chris@0 1273 else
Chris@0 1274 return unless config('shebang') == 'all'
Chris@0 1275 new = Shebang.new(config('rubypath'))
Chris@0 1276 end
Chris@0 1277 $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
Chris@0 1278 open_atomic_writer(path) {|output|
Chris@0 1279 File.open(path, 'rb') {|f|
Chris@0 1280 f.gets if old # discard
Chris@0 1281 output.puts new.to_s
Chris@0 1282 output.print f.read
Chris@0 1283 }
Chris@0 1284 }
Chris@0 1285 end
Chris@0 1286
Chris@0 1287 def new_shebang(old)
Chris@0 1288 if /\Aruby/ =~ File.basename(old.cmd)
Chris@0 1289 Shebang.new(config('rubypath'), old.args)
Chris@0 1290 elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
Chris@0 1291 Shebang.new(config('rubypath'), old.args[1..-1])
Chris@0 1292 else
Chris@0 1293 return old unless config('shebang') == 'all'
Chris@0 1294 Shebang.new(config('rubypath'))
Chris@0 1295 end
Chris@0 1296 end
Chris@0 1297
Chris@0 1298 def open_atomic_writer(path, &block)
Chris@0 1299 tmpfile = File.basename(path) + '.tmp'
Chris@0 1300 begin
Chris@0 1301 File.open(tmpfile, 'wb', &block)
Chris@0 1302 File.rename tmpfile, File.basename(path)
Chris@0 1303 ensure
Chris@0 1304 File.unlink tmpfile if File.exist?(tmpfile)
Chris@0 1305 end
Chris@0 1306 end
Chris@0 1307
Chris@0 1308 class Shebang
Chris@0 1309 def Shebang.load(path)
Chris@0 1310 line = nil
Chris@0 1311 File.open(path) {|f|
Chris@0 1312 line = f.gets
Chris@0 1313 }
Chris@0 1314 return nil unless /\A#!/ =~ line
Chris@0 1315 parse(line)
Chris@0 1316 end
Chris@0 1317
Chris@0 1318 def Shebang.parse(line)
Chris@0 1319 cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
Chris@0 1320 new(cmd, args)
Chris@0 1321 end
Chris@0 1322
Chris@0 1323 def initialize(cmd, args = [])
Chris@0 1324 @cmd = cmd
Chris@0 1325 @args = args
Chris@0 1326 end
Chris@0 1327
Chris@0 1328 attr_reader :cmd
Chris@0 1329 attr_reader :args
Chris@0 1330
Chris@0 1331 def to_s
Chris@0 1332 "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
Chris@0 1333 end
Chris@0 1334 end
Chris@0 1335
Chris@0 1336 #
Chris@0 1337 # TASK install
Chris@0 1338 #
Chris@0 1339
Chris@0 1340 def exec_install
Chris@0 1341 rm_f 'InstalledFiles'
Chris@0 1342 exec_task_traverse 'install'
Chris@0 1343 end
Chris@0 1344
Chris@0 1345 def install_dir_bin(rel)
Chris@0 1346 install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
Chris@0 1347 end
Chris@0 1348
Chris@0 1349 def install_dir_lib(rel)
Chris@0 1350 install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
Chris@0 1351 end
Chris@0 1352
Chris@0 1353 def install_dir_ext(rel)
Chris@0 1354 return unless extdir?(curr_srcdir())
Chris@0 1355 install_files rubyextentions('.'),
Chris@0 1356 "#{config('sodir')}/#{File.dirname(rel)}",
Chris@0 1357 0555
Chris@0 1358 end
Chris@0 1359
Chris@0 1360 def install_dir_data(rel)
Chris@0 1361 install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
Chris@0 1362 end
Chris@0 1363
Chris@0 1364 def install_dir_conf(rel)
Chris@0 1365 # FIXME: should not remove current config files
Chris@0 1366 # (rename previous file to .old/.org)
Chris@0 1367 install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
Chris@0 1368 end
Chris@0 1369
Chris@0 1370 def install_dir_man(rel)
Chris@0 1371 install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
Chris@0 1372 end
Chris@0 1373
Chris@0 1374 def install_files(list, dest, mode)
Chris@0 1375 mkdir_p dest, @config.install_prefix
Chris@0 1376 list.each do |fname|
Chris@0 1377 install fname, dest, mode, @config.install_prefix
Chris@0 1378 end
Chris@0 1379 end
Chris@0 1380
Chris@0 1381 def libfiles
Chris@0 1382 glob_reject(%w(*.y *.output), targetfiles())
Chris@0 1383 end
Chris@0 1384
Chris@0 1385 def rubyextentions(dir)
Chris@0 1386 ents = glob_select("*.#{@config.dllext}", targetfiles())
Chris@0 1387 if ents.empty?
Chris@0 1388 setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
Chris@0 1389 end
Chris@0 1390 ents
Chris@0 1391 end
Chris@0 1392
Chris@0 1393 def targetfiles
Chris@0 1394 mapdir(existfiles() - hookfiles())
Chris@0 1395 end
Chris@0 1396
Chris@0 1397 def mapdir(ents)
Chris@0 1398 ents.map {|ent|
Chris@0 1399 if File.exist?(ent)
Chris@0 1400 then ent # objdir
Chris@0 1401 else "#{curr_srcdir()}/#{ent}" # srcdir
Chris@0 1402 end
Chris@0 1403 }
Chris@0 1404 end
Chris@0 1405
Chris@0 1406 # picked up many entries from cvs-1.11.1/src/ignore.c
Chris@0 1407 JUNK_FILES = %w(
Chris@0 1408 core RCSLOG tags TAGS .make.state
Chris@0 1409 .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
Chris@0 1410 *~ *.old *.bak *.BAK *.orig *.rej _$* *$
Chris@0 1411
Chris@0 1412 *.org *.in .*
Chris@0 1413 )
Chris@0 1414
Chris@0 1415 def existfiles
Chris@0 1416 glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
Chris@0 1417 end
Chris@0 1418
Chris@0 1419 def hookfiles
Chris@0 1420 %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
Chris@0 1421 %w( config setup install clean ).map {|t| sprintf(fmt, t) }
Chris@0 1422 }.flatten
Chris@0 1423 end
Chris@0 1424
Chris@0 1425 def glob_select(pat, ents)
Chris@0 1426 re = globs2re([pat])
Chris@0 1427 ents.select {|ent| re =~ ent }
Chris@0 1428 end
Chris@0 1429
Chris@0 1430 def glob_reject(pats, ents)
Chris@0 1431 re = globs2re(pats)
Chris@0 1432 ents.reject {|ent| re =~ ent }
Chris@0 1433 end
Chris@0 1434
Chris@0 1435 GLOB2REGEX = {
Chris@0 1436 '.' => '\.',
Chris@0 1437 '$' => '\$',
Chris@0 1438 '#' => '\#',
Chris@0 1439 '*' => '.*'
Chris@0 1440 }
Chris@0 1441
Chris@0 1442 def globs2re(pats)
Chris@0 1443 /\A(?:#{
Chris@0 1444 pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
Chris@0 1445 })\z/
Chris@0 1446 end
Chris@0 1447
Chris@0 1448 #
Chris@0 1449 # TASK test
Chris@0 1450 #
Chris@0 1451
Chris@0 1452 TESTDIR = 'test'
Chris@0 1453
Chris@0 1454 def exec_test
Chris@0 1455 unless File.directory?('test')
Chris@0 1456 $stderr.puts 'no test in this package' if verbose?
Chris@0 1457 return
Chris@0 1458 end
Chris@0 1459 $stderr.puts 'Running tests...' if verbose?
Chris@0 1460 begin
Chris@0 1461 require 'test/unit'
Chris@0 1462 rescue LoadError
Chris@0 1463 setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
Chris@0 1464 end
Chris@0 1465 runner = Test::Unit::AutoRunner.new(true)
Chris@0 1466 runner.to_run << TESTDIR
Chris@0 1467 runner.run
Chris@0 1468 end
Chris@0 1469
Chris@0 1470 #
Chris@0 1471 # TASK clean
Chris@0 1472 #
Chris@0 1473
Chris@0 1474 def exec_clean
Chris@0 1475 exec_task_traverse 'clean'
Chris@0 1476 rm_f @config.savefile
Chris@0 1477 rm_f 'InstalledFiles'
Chris@0 1478 end
Chris@0 1479
Chris@0 1480 alias clean_dir_bin noop
Chris@0 1481 alias clean_dir_lib noop
Chris@0 1482 alias clean_dir_data noop
Chris@0 1483 alias clean_dir_conf noop
Chris@0 1484 alias clean_dir_man noop
Chris@0 1485
Chris@0 1486 def clean_dir_ext(rel)
Chris@0 1487 return unless extdir?(curr_srcdir())
Chris@0 1488 make 'clean' if File.file?('Makefile')
Chris@0 1489 end
Chris@0 1490
Chris@0 1491 #
Chris@0 1492 # TASK distclean
Chris@0 1493 #
Chris@0 1494
Chris@0 1495 def exec_distclean
Chris@0 1496 exec_task_traverse 'distclean'
Chris@0 1497 rm_f @config.savefile
Chris@0 1498 rm_f 'InstalledFiles'
Chris@0 1499 end
Chris@0 1500
Chris@0 1501 alias distclean_dir_bin noop
Chris@0 1502 alias distclean_dir_lib noop
Chris@0 1503
Chris@0 1504 def distclean_dir_ext(rel)
Chris@0 1505 return unless extdir?(curr_srcdir())
Chris@0 1506 make 'distclean' if File.file?('Makefile')
Chris@0 1507 end
Chris@0 1508
Chris@0 1509 alias distclean_dir_data noop
Chris@0 1510 alias distclean_dir_conf noop
Chris@0 1511 alias distclean_dir_man noop
Chris@0 1512
Chris@0 1513 #
Chris@0 1514 # Traversing
Chris@0 1515 #
Chris@0 1516
Chris@0 1517 def exec_task_traverse(task)
Chris@0 1518 run_hook "pre-#{task}"
Chris@0 1519 FILETYPES.each do |type|
Chris@0 1520 if type == 'ext' and config('without-ext') == 'yes'
Chris@0 1521 $stderr.puts 'skipping ext/* by user option' if verbose?
Chris@0 1522 next
Chris@0 1523 end
Chris@0 1524 traverse task, type, "#{task}_dir_#{type}"
Chris@0 1525 end
Chris@0 1526 run_hook "post-#{task}"
Chris@0 1527 end
Chris@0 1528
Chris@0 1529 def traverse(task, rel, mid)
Chris@0 1530 dive_into(rel) {
Chris@0 1531 run_hook "pre-#{task}"
Chris@0 1532 __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
Chris@0 1533 directories_of(curr_srcdir()).each do |d|
Chris@0 1534 traverse task, "#{rel}/#{d}", mid
Chris@0 1535 end
Chris@0 1536 run_hook "post-#{task}"
Chris@0 1537 }
Chris@0 1538 end
Chris@0 1539
Chris@0 1540 def dive_into(rel)
Chris@0 1541 return unless File.dir?("#{@srcdir}/#{rel}")
Chris@0 1542
Chris@0 1543 dir = File.basename(rel)
Chris@0 1544 Dir.mkdir dir unless File.dir?(dir)
Chris@0 1545 prevdir = Dir.pwd
Chris@0 1546 Dir.chdir dir
Chris@0 1547 $stderr.puts '---> ' + rel if verbose?
Chris@0 1548 @currdir = rel
Chris@0 1549 yield
Chris@0 1550 Dir.chdir prevdir
Chris@0 1551 $stderr.puts '<--- ' + rel if verbose?
Chris@0 1552 @currdir = File.dirname(rel)
Chris@0 1553 end
Chris@0 1554
Chris@0 1555 def run_hook(id)
Chris@0 1556 path = [ "#{curr_srcdir()}/#{id}",
Chris@0 1557 "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
Chris@0 1558 return unless path
Chris@0 1559 begin
Chris@0 1560 instance_eval File.read(path), path, 1
Chris@0 1561 rescue
Chris@0 1562 raise if $DEBUG
Chris@0 1563 setup_rb_error "hook #{path} failed:\n" + $!.message
Chris@0 1564 end
Chris@0 1565 end
Chris@0 1566
Chris@0 1567 end # class Installer
Chris@0 1568
Chris@0 1569
Chris@0 1570 class SetupError < StandardError; end
Chris@0 1571
Chris@0 1572 def setup_rb_error(msg)
Chris@0 1573 raise SetupError, msg
Chris@0 1574 end
Chris@0 1575
Chris@0 1576 if $0 == __FILE__
Chris@0 1577 begin
Chris@0 1578 ToplevelInstaller.invoke
Chris@0 1579 rescue SetupError
Chris@0 1580 raise if $DEBUG
Chris@0 1581 $stderr.puts $!.message
Chris@0 1582 $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
Chris@0 1583 exit 1
Chris@0 1584 end
Chris@0 1585 end