annotate vendor/gems/rubytree-0.5.2/setup.rb @ 8:0c83d98252d9 yuya

* Add custom repo prefix and proper auth realm, remove auth cache (seems like an unwise feature), pass DB handle around, various other bits of tidying
author Chris Cannam
date Thu, 12 Aug 2010 15:31:37 +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