annotate .svn/pristine/1c/1c5257cafbf7d7508949bf6ef73182b08b1fa87d.svn-base @ 1082:997f6d7738f7 bug_531

In repo controller entry action, show the page for the file even if it's binary (so user still has access to history etc links). This makes it possible to use the entry action as the default when a file is clicked on
author Chris Cannam <chris.cannam@soundsoftware.ac.uk>
date Thu, 22 Nov 2012 18:04:17 +0000
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