annotate .svn/pristine/1c/1c5257cafbf7d7508949bf6ef73182b08b1fa87d.svn-base @ 1327:287f201c2802 redmine-2.2-integration

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