| CODENOTIFIER | HelpYou are not signed inSign in |
Project: taskr
Revision: 4
Author: matt.zukowski
Date: 26 Nov 2007 20:55:48
Changes:Initial import.
Files:| ... | ...@@ -0,0 +1,8 @@ | |
| 1 | module Taskr::Helpers | |
| 2 | def taskr_response_xml(result, &block) | |
| 3 | instruct! | |
| 4 | tag!("response", 'result' => result, 'xmlns:taskr' => "http://taskr.googlecode.com") do | |
| 5 | yield | |
| 6 | end | |
| 7 | end | |
| 8 | end | |
| 0 | 9 | \ No newline at end of file |
| ... | ...@@ -0,0 +1,2 @@ | |
| 1 | require 'test/unit' | |
| 2 | require File.dirname(__FILE__) + '/../lib/taskr' |
| ... | ...@@ -0,0 +1,1585 @@ | |
| 1 | # | |
| 2 | # setup.rb | |
| 3 | # | |
| 4 | # Copyright (c) 2000-2005 Minero Aoki | |
| 5 | # | |
| 6 | # This program is free software. | |
| 7 | # You can distribute/modify this program under the terms of | |
| 8 | # the GNU LGPL, Lesser General Public License version 2.1. | |
| 9 | # | |
| 10 | ||
| 11 | unless Enumerable.method_defined?(:map) # Ruby 1.4.6 | |
| 12 | module Enumerable | |
| 13 | alias map collect | |
| 14 | end | |
| 15 | end | |
| 16 | ||
| 17 | unless File.respond_to?(:read) # Ruby 1.6 | |
| 18 | def File.read(fname) | |
| 19 | open(fname) {|f| | |
| 20 | return f.read | |
| 21 | } | |
| 22 | end | |
| 23 | end | |
| 24 | ||
| 25 | unless Errno.const_defined?(:ENOTEMPTY) # Windows? | |
| 26 | module Errno | |
| 27 | class ENOTEMPTY | |
| 28 | # We do not raise this exception, implementation is not needed. | |
| 29 | end | |
| 30 | end | |
| 31 | end | |
| 32 | ||
| 33 | def File.binread(fname) | |
| 34 | open(fname, 'rb') {|f| | |
| 35 | return f.read | |
| 36 | } | |
| 37 | end | |
| 38 | ||
| 39 | # for corrupted Windows' stat(2) | |
| 40 | def File.dir?(path) | |
| 41 | File.directory?((path[-1,1] == '/') ? path : path + '/') | |
| 42 | end | |
| 43 | ||
| 44 | ||
| 45 | class ConfigTable | |
| 46 | ||
| 47 | include Enumerable | |
| 48 | ||
| 49 | def initialize(rbconfig) | |
| 50 | @rbconfig = rbconfig | |
| 51 | @items = [] | |
| 52 | @table = {} | |
| 53 | # options | |
| 54 | @install_prefix = nil | |
| 55 | @config_opt = nil | |
| 56 | @verbose = true | |
| 57 | @no_harm = false | |
| 58 | end | |
| 59 | ||
| 60 | attr_accessor :install_prefix | |
| 61 | attr_accessor :config_opt | |
| 62 | ||
| 63 | attr_writer :verbose | |
| 64 | ||
| 65 | def verbose? | |
| 66 | @verbose | |
| 67 | end | |
| 68 | ||
| 69 | attr_writer :no_harm | |
| 70 | ||
| 71 | def no_harm? | |
| 72 | @no_harm | |
| 73 | end | |
| 74 | ||
| 75 | def [](key) | |
| 76 | lookup(key).resolve(self) | |
| 77 | end | |
| 78 | ||
| 79 | def []=(key, val) | |
| 80 | lookup(key).set val | |
| 81 | end | |
| 82 | ||
| 83 | def names | |
| 84 | @items.map {|i| i.name } | |
| 85 | end | |
| 86 | ||
| 87 | def each(&block) | |
| 88 | @items.each(&block) | |
| 89 | end | |
| 90 | ||
| 91 | def key?(name) | |
| 92 | @table.key?(name) | |
| 93 | end | |
| 94 | ||
| 95 | def lookup(name) | |
| 96 | @table[name] or setup_rb_error "no such config item: #{name}" | |
| 97 | end | |
| 98 | ||
| 99 | def add(item) | |
| 100 | @items.push item | |
| 101 | @table[item.name] = item | |
| 102 | end | |
| 103 | ||
| 104 | def remove(name) | |
| 105 | item = lookup(name) | |
| 106 | @items.delete_if {|i| i.name == name } | |
| 107 | @table.delete_if {|name, i| i.name == name } | |
| 108 | item | |
| 109 | end | |
| 110 | ||
| 111 | def load_script(path, inst = nil) | |
| 112 | if File.file?(path) | |
| 113 | MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path | |
| 114 | end | |
| 115 | end | |
| 116 | ||
| 117 | def savefile | |
| 118 | '.config' | |
| 119 | end | |
| 120 | ||
| 121 | def load_savefile | |
| 122 | begin | |
| 123 | File.foreach(savefile()) do |line| | |
| 124 | k, v = *line.split(/=/, 2) | |
| 125 | self[k] = v.strip | |
| 126 | end | |
| 127 | rescue Errno::ENOENT | |
| 128 | setup_rb_error $!.message + "\n#{File.basename($0)} config first" | |
| 129 | end | |
| 130 | end | |
| 131 | ||
| 132 | def save | |
| 133 | @items.each {|i| i.value } | |
| 134 | File.open(savefile(), 'w') {|f| | |
| 135 | @items.each do |i| | |
| 136 | f.printf "%s=%s\n", i.name, i.value if i.value? and i.value | |
| 137 | end | |
| 138 | } | |
| 139 | end | |
| 140 | ||
| 141 | def load_standard_entries | |
| 142 | standard_entries(@rbconfig).each do |ent| | |
| 143 | add ent | |
| 144 | end | |
| 145 | end | |
| 146 | ||
| 147 | def standard_entries(rbconfig) | |
| 148 | c = rbconfig | |
| 149 | ||
| 150 | rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) | |
| 151 | ||
| 152 | major = c['MAJOR'].to_i | |
| 153 | minor = c['MINOR'].to_i | |
| 154 | teeny = c['TEENY'].to_i | |
| 155 | version = "#{major}.#{minor}" | |
| 156 | ||
| 157 | # ruby ver. >= 1.4.4? | |
| 158 | newpath_p = ((major >= 2) or | |
| 159 | ((major == 1) and | |
| 160 | ((minor >= 5) or | |
| 161 | ((minor == 4) and (teeny >= 4))))) | |
| 162 | ||
| 163 | if c['rubylibdir'] | |
| 164 | # V > 1.6.3 | |
| 165 | libruby = "#{c['prefix']}/lib/ruby" | |
| 166 | librubyver = c['rubylibdir'] | |
| 167 | librubyverarch = c['archdir'] | |
| 168 | siteruby = c['sitedir'] | |
| 169 | siterubyver = c['sitelibdir'] | |
| 170 | siterubyverarch = c['sitearchdir'] | |
| 171 | elsif newpath_p | |
| 172 | # 1.4.4 <= V <= 1.6.3 | |
| 173 | libruby = "#{c['prefix']}/lib/ruby" | |
| 174 | librubyver = "#{c['prefix']}/lib/ruby/#{version}" | |
| 175 | librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" | |
| 176 | siteruby = c['sitedir'] | |
| 177 | siterubyver = "$siteruby/#{version}" | |
| 178 | siterubyverarch = "$siterubyver/#{c['arch']}" | |
| 179 | else | |
| 180 | # V < 1.4.4 | |
| 181 | libruby = "#{c['prefix']}/lib/ruby" | |
| 182 | librubyver = "#{c['prefix']}/lib/ruby/#{version}" | |
| 183 | librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" | |
| 184 | siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" | |
| 185 | siterubyver = siteruby | |
| 186 | siterubyverarch = "$siterubyver/#{c['arch']}" | |
| 187 | end | |
| 188 | parameterize = lambda {|path| | |
| 189 | path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') | |
| 190 | } | |
| 191 | ||
| 192 | if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } | |
| 193 | makeprog = arg.sub(/'/, '').split(/=/, 2)[1] | |
| 194 | else | |
| 195 | makeprog = 'make' | |
| 196 | end | |
| 197 | ||
| 198 | [ | |
| 199 | ExecItem.new('installdirs', 'std/site/home', | |
| 200 | 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ | |
| 201 | {|val, table| | |
| 202 | case val | |
| 203 | when 'std' | |
| 204 | table['rbdir'] = '$librubyver' | |
| 205 | table['sodir'] = '$librubyverarch' | |
| 206 | when 'site' | |
| 207 | table['rbdir'] = '$siterubyver' | |
| 208 | table['sodir'] = '$siterubyverarch' | |
| 209 | when 'home' | |
| 210 | setup_rb_error '$HOME was not set' unless ENV['HOME'] | |
| 211 | table['prefix'] = ENV['HOME'] | |
| 212 | table['rbdir'] = '$libdir/ruby' | |
| 213 | table['sodir'] = '$libdir/ruby' | |
| 214 | end | |
| 215 | }, | |
| 216 | PathItem.new('prefix', 'path', c['prefix'], | |
| 217 | 'path prefix of target environment'), | |
| 218 | PathItem.new('bindir', 'path', parameterize.call(c['bindir']), | |
| 219 | 'the directory for commands'), | |
| 220 | PathItem.new('libdir', 'path', parameterize.call(c['libdir']), | |
| 221 | 'the directory for libraries'), | |
| 222 | PathItem.new('datadir', 'path', parameterize.call(c['datadir']), | |
| 223 | 'the directory for shared data'), | |
| 224 | PathItem.new('mandir', 'path', parameterize.call(c['mandir']), | |
| 225 | 'the directory for man pages'), | |
| 226 | PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), | |
| 227 | 'the directory for system configuration files'), | |
| 228 | PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), | |
| 229 | 'the directory for local state data'), | |
| 230 | PathItem.new('libruby', 'path', libruby, | |
| 231 | 'the directory for ruby libraries'), | |
| 232 | PathItem.new('librubyver', 'path', librubyver, | |
| 233 | 'the directory for standard ruby libraries'), | |
| 234 | PathItem.new('librubyverarch', 'path', librubyverarch, | |
| 235 | 'the directory for standard ruby extensions'), | |
| 236 | PathItem.new('siteruby', 'path', siteruby, | |
| 237 | 'the directory for version-independent aux ruby libraries'), | |
| 238 | PathItem.new('siterubyver', 'path', siterubyver, | |
| 239 | 'the directory for aux ruby libraries'), | |
| 240 | PathItem.new('siterubyverarch', 'path', siterubyverarch, | |
| 241 | 'the directory for aux ruby binaries'), | |
| 242 | PathItem.new('rbdir', 'path', '$siterubyver', | |
| 243 | 'the directory for ruby scripts'), | |
| 244 | PathItem.new('sodir', 'path', '$siterubyverarch', | |
| 245 | 'the directory for ruby extentions'), | |
| 246 | PathItem.new('rubypath', 'path', rubypath, | |
| 247 | 'the path to set to #! line'), | |
| 248 | ProgramItem.new('rubyprog', 'name', rubypath, | |
| 249 | 'the ruby program using for installation'), | |
| 250 | ProgramItem.new('makeprog', 'name', makeprog, | |
| 251 | 'the make program to compile ruby extentions'), | |
| 252 | SelectItem.new('shebang', 'all/ruby/never', 'ruby', | |
| 253 | 'shebang line (#!) editing mode'), | |
| 254 | BoolItem.new('without-ext', 'yes/no', 'no', | |
| 255 | 'does not compile/install ruby extentions') | |
| 256 | ] | |
| 257 | end | |
| 258 | private :standard_entries | |
| 259 | ||
| 260 | def load_multipackage_entries | |
| 261 | multipackage_entries().each do |ent| | |
| 262 | add ent | |
| 263 | end | |
| 264 | end | |
| 265 | ||
| 266 | def multipackage_entries | |
| 267 | [ | |
| 268 | PackageSelectionItem.new('with', 'name,name...', '', 'ALL', | |
| 269 | 'package names that you want to install'), | |
| 270 | PackageSelectionItem.new('without', 'name,name...', '', 'NONE', | |
| 271 | 'package names that you do not want to install') | |
| 272 | ] | |
| 273 | end | |
| 274 | private :multipackage_entries | |
| 275 | ||
| 276 | ALIASES = { | |
| 277 | 'std-ruby' => 'librubyver', | |
| 278 | 'stdruby' => 'librubyver', | |
| 279 | 'rubylibdir' => 'librubyver', | |
| 280 | 'archdir' => 'librubyverarch', | |
| 281 | 'site-ruby-common' => 'siteruby', # For backward compatibility | |
| 282 | 'site-ruby' => 'siterubyver', # For backward compatibility | |
| 283 | 'bin-dir' => 'bindir', | |
| 284 | 'bin-dir' => 'bindir', | |
| 285 | 'rb-dir' => 'rbdir', | |
| 286 | 'so-dir' => 'sodir', | |
| 287 | 'data-dir' => 'datadir', | |
| 288 | 'ruby-path' => 'rubypath', | |
| 289 | 'ruby-prog' => 'rubyprog', | |
| 290 | 'ruby' => 'rubyprog', | |
| 291 | 'make-prog' => 'makeprog', | |
| 292 | 'make' => 'makeprog' | |
| 293 | } | |
| 294 | ||
| 295 | def fixup | |
| 296 | ALIASES.each do |ali, name| | |
| 297 | @table[ali] = @table[name] | |
| 298 | end | |
| 299 | @items.freeze | |
| 300 | @table.freeze | |
| 301 | @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ | |
| 302 | end | |
| 303 | ||
| 304 | def parse_opt(opt) | |
| 305 | m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" | |
| 306 | m.to_a[1,2] | |
| 307 | end | |
| 308 | ||
| 309 | def dllext | |
| 310 | @rbconfig['DLEXT'] | |
| 311 | end | |
| 312 | ||
| 313 | def value_config?(name) | |
| 314 | lookup(name).value? | |
| 315 | end | |
| 316 | ||
| 317 | class Item | |
| 318 | def initialize(name, template, default, desc) | |
| 319 | @name = name.freeze | |
| 320 | @template = template | |
| 321 | @value = default | |
| 322 | @default = default | |
| 323 | @description = desc | |
| 324 | end | |
| 325 | ||
| 326 | attr_reader :name | |
| 327 | attr_reader :description | |
| 328 | ||
| 329 | attr_accessor :default | |
| 330 | alias help_default default | |
| 331 | ||
| 332 | def help_opt | |
| 333 | "--#{@name}=#{@template}" | |
| 334 | end | |
| 335 | ||
| 336 | def value? | |
| 337 | true | |
| 338 | end | |
| 339 | ||
| 340 | def value | |
| 341 | @value | |
| 342 | end | |
| 343 | ||
| 344 | def resolve(table) | |
| 345 | @value.gsub(%r<\$([^/]+)>) { table[$1] } | |
| 346 | end | |
| 347 | ||
| 348 | def set(val) | |
| 349 | @value = check(val) | |
| 350 | end | |
| 351 | ||
| 352 | private | |
| 353 | ||
| 354 | def check(val) | |
| 355 | setup_rb_error "config: --#{name} requires argument" unless val | |
| 356 | val | |
| 357 | end | |
| 358 | end | |
| 359 | ||
| 360 | class BoolItem < Item | |
| 361 | def config_type | |
| 362 | 'bool' | |
| 363 | end | |
| 364 | ||
| 365 | def help_opt | |
| 366 | "--#{@name}" | |
| 367 | end | |
| 368 | ||
| 369 | private | |
| 370 | ||
| 371 | def check(val) | |
| 372 | return 'yes' unless val | |
| 373 | case val | |
| 374 | when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' | |
| 375 | when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' | |
| 376 | else | |
| 377 | setup_rb_error "config: --#{@name} accepts only yes/no for argument" | |
| 378 | end | |
| 379 | end | |
| 380 | end | |
| 381 | ||
| 382 | class PathItem < Item | |
| 383 | def config_type | |
| 384 | 'path' | |
| 385 | end | |
| 386 | ||
| 387 | private | |
| 388 | ||
| 389 | def check(path) | |
| 390 | setup_rb_error "config: --#{@name} requires argument" unless path | |
| 391 | path[0,1] == '$' ? path : File.expand_path(path) | |
| 392 | end | |
| 393 | end | |
| 394 | ||
| 395 | class ProgramItem < Item | |
| 396 | def config_type | |
| 397 | 'program' | |
| 398 | end | |
| 399 | end | |
| 400 | ||
| 401 | class SelectItem < Item | |
| 402 | def initialize(name, selection, default, desc) | |
| 403 | super | |
| 404 | @ok = selection.split('/') | |
| 405 | end | |
| 406 | ||
| 407 | def config_type | |
| 408 | 'select' | |
| 409 | end | |
| 410 | ||
| 411 | private | |
| 412 | ||
| 413 | def check(val) | |
| 414 | unless @ok.include?(val.strip) | |
| 415 | setup_rb_error "config: use --#{@name}=#{@template} (#{val})" | |
| 416 | end | |
| 417 | val.strip | |
| 418 | end | |
| 419 | end | |
| 420 | ||
| 421 | class ExecItem < Item | |
| 422 | def initialize(name, selection, desc, &block) | |
| 423 | super name, selection, nil, desc | |
| 424 | @ok = selection.split('/') | |
| 425 | @action = block | |
| 426 | end | |
| 427 | ||
| 428 | def config_type | |
| 429 | 'exec' | |
| 430 | end | |
| 431 | ||
| 432 | def value? | |
| 433 | false | |
| 434 | end | |
| 435 | ||
| 436 | def resolve(table) | |
| 437 | setup_rb_error "$#{name()} wrongly used as option value" | |
| 438 | end | |
| 439 | ||
| 440 | undef set | |
| 441 | ||
| 442 | def evaluate(val, table) | |
| 443 | v = val.strip.downcase | |
| 444 | unless @ok.include?(v) | |
| 445 | setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" | |
| 446 | end | |
| 447 | @action.call v, table | |
| 448 | end | |
| 449 | end | |
| 450 | ||
| 451 | class PackageSelectionItem < Item | |
| 452 | def initialize(name, template, default, help_default, desc) | |
| 453 | super name, template, default, desc | |
| 454 | @help_default = help_default | |
| 455 | end | |
| 456 | ||
| 457 | attr_reader :help_default | |
| 458 | ||
| 459 | def config_type | |
| 460 | 'package' | |
| 461 | end | |
| 462 | ||
| 463 | private | |
| 464 | ||
| 465 | def check(val) | |
| 466 | unless File.dir?("packages/#{val}") | |
| 467 | setup_rb_error "config: no such package: #{val}" | |
| 468 | end | |
| 469 | val | |
| 470 | end | |
| 471 | end | |
| 472 | ||
| 473 | class MetaConfigEnvironment | |
| 474 | def initialize(config, installer) | |
| 475 | @config = config | |
| 476 | @installer = installer | |
| 477 | end | |
| 478 | ||
| 479 | def config_names | |
| 480 | @config.names | |
| 481 | end | |
| 482 | ||
| 483 | def config?(name) | |
| 484 | @config.key?(name) | |
| 485 | end | |
| 486 | ||
| 487 | def bool_config?(name) | |
| 488 | @config.lookup(name).config_type == 'bool' | |
| 489 | end | |
| 490 | ||
| 491 | def path_config?(name) | |
| 492 | @config.lookup(name).config_type == 'path' | |
| 493 | end | |
| 494 | ||
| 495 | def value_config?(name) | |
| 496 | @config.lookup(name).config_type != 'exec' | |
| 497 | end | |
| 498 | ||
| 499 | def add_config(item) | |
| 500 | @config.add item | |
| 501 | end | |
| 502 | ||
| 503 | def add_bool_config(name, default, desc) | |
| 504 | @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) | |
| 505 | end | |
| 506 | ||
| 507 | def add_path_config(name, default, desc) | |
| 508 | @config.add PathItem.new(name, 'path', default, desc) | |
| 509 | end | |
| 510 | ||
| 511 | def set_config_default(name, default) | |
| 512 | @config.lookup(name).default = default | |
| 513 | end | |
| 514 | ||
| 515 | def remove_config(name) | |
| 516 | @config.remove(name) | |
| 517 | end | |
| 518 | ||
| 519 | # For only multipackage | |
| 520 | def packages | |
| 521 | raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer | |
| 522 | @installer.packages | |
| 523 | end | |
| 524 | ||
| 525 | # For only multipackage | |
| 526 | def declare_packages(list) | |
| 527 | raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer | |
| 528 | @installer.packages = list | |
| 529 | end | |
| 530 | end | |
| 531 | ||
| 532 | end # class ConfigTable | |
| 533 | ||
| 534 | ||
| 535 | # This module requires: #verbose?, #no_harm? | |
| 536 | module FileOperations | |
| 537 | ||
| 538 | def mkdir_p(dirname, prefix = nil) | |
| 539 | dirname = prefix + File.expand_path(dirname) if prefix | |
| 540 | $stderr.puts "mkdir -p #{dirname}" if verbose? | |
| 541 | return if no_harm? | |
| 542 | ||
| 543 | # Does not check '/', it's too abnormal. | |
| 544 | dirs = File.expand_path(dirname).split(%r<(?=/)>) | |
| 545 | if /\A[a-z]:\z/i =~ dirs[0] | |
| 546 | disk = dirs.shift | |
| 547 | dirs[0] = disk + dirs[0] | |
| 548 | end | |
| 549 | dirs.each_index do |idx| | |
| 550 | path = dirs[0..idx].join('') | |
| 551 | Dir.mkdir path unless File.dir?(path) | |
| 552 | end | |
| 553 | end | |
| 554 | ||
| 555 | def rm_f(path) | |
| 556 | $stderr.puts "rm -f #{path}" if verbose? | |
| 557 | return if no_harm? | |
| 558 | force_remove_file path | |
| 559 | end | |
| 560 | ||
| 561 | def rm_rf(path) | |
| 562 | $stderr.puts "rm -rf #{path}" if verbose? | |
| 563 | return if no_harm? | |
| 564 | remove_tree path | |
| 565 | end | |
| 566 | ||
| 567 | def remove_tree(path) | |
| 568 | if File.symlink?(path) | |
| 569 | remove_file path | |
| 570 | elsif File.dir?(path) | |
| 571 | remove_tree0 path | |
| 572 | else | |
| 573 | force_remove_file path | |
| 574 | end | |
| 575 | end | |
| 576 | ||
| 577 | def remove_tree0(path) | |
| 578 | Dir.foreach(path) do |ent| | |
| 579 | next if ent == '.' | |
| 580 | next if ent == '..' | |
| 581 | entpath = "#{path}/#{ent}" | |
| 582 | if File.symlink?(entpath) | |
| 583 | remove_file entpath | |
| 584 | elsif File.dir?(entpath) | |
| 585 | remove_tree0 entpath | |
| 586 | else | |
| 587 | force_remove_file entpath | |
| 588 | end | |
| 589 | end | |
| 590 | begin | |
| 591 | Dir.rmdir path | |
| 592 | rescue Errno::ENOTEMPTY | |
| 593 | # directory may not be empty | |
| 594 | end | |
| 595 | end | |
| 596 | ||
| 597 | def move_file(src, dest) | |
| 598 | force_remove_file dest | |
| 599 | begin | |
| 600 | File.rename src, dest | |
| 601 | rescue | |
| 602 | File.open(dest, 'wb') {|f| | |
| 603 | f.write File.binread(src) | |
| 604 | } | |
| 605 | File.chmod File.stat(src).mode, dest | |
| 606 | File.unlink src | |
| 607 | end | |
| 608 | end | |
| 609 | ||
| 610 | def force_remove_file(path) | |
| 611 | begin | |
| 612 | remove_file path | |
| 613 | rescue | |
| 614 | end | |
| 615 | end | |
| 616 | ||
| 617 | def remove_file(path) | |
| 618 | File.chmod 0777, path | |
| 619 | File.unlink path | |
| 620 | end | |
| 621 | ||
| 622 | def install(from, dest, mode, prefix = nil) | |
| 623 | $stderr.puts "install #{from} #{dest}" if verbose? | |
| 624 | return if no_harm? | |
| 625 | ||
| 626 | realdest = prefix ? prefix + File.expand_path(dest) : dest | |
| 627 | realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) | |
| 628 | str = File.binread(from) | |
| 629 | if diff?(str, realdest) | |
| 630 | verbose_off { | |
| 631 | rm_f realdest if File.exist?(realdest) | |
| 632 | } | |
| 633 | File.open(realdest, 'wb') {|f| | |
| 634 | f.write str | |
| 635 | } | |
| 636 | File.chmod mode, realdest | |
| 637 | ||
| 638 | File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| | |
| 639 | if prefix | |
| 640 | f.puts realdest.sub(prefix, '') | |
| 641 | else | |
| 642 | f.puts realdest | |
| 643 | end | |
| 644 | } | |
| 645 | end | |
| 646 | end | |
| 647 | ||
| 648 | def diff?(new_content, path) | |
| 649 | return true unless File.exist?(path) | |
| 650 | new_content != File.binread(path) | |
| 651 | end | |
| 652 | ||
| 653 | def command(*args) | |
| 654 | $stderr.puts args.join(' ') if verbose? | |
| 655 | system(*args) or raise RuntimeError, | |
| 656 | "system(#{args.map{|a| a.inspect }.join(' ')}) failed" | |
| 657 | end | |
| 658 | ||
| 659 | def ruby(*args) | |
| 660 | command config('rubyprog'), *args | |
| 661 | end | |
| 662 | ||
| 663 | def make(task = nil) | |
| 664 | command(*[config('makeprog'), task].compact) | |
| 665 | end | |
| 666 | ||
| 667 | def extdir?(dir) | |
| 668 | File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") | |
| 669 | end | |
| 670 | ||
| 671 | def files_of(dir) | |
| 672 | Dir.open(dir) {|d| | |
| 673 | return d.select {|ent| File.file?("#{dir}/#{ent}") } | |
| 674 | } | |
| 675 | end | |
| 676 | ||
| 677 | DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) | |
| 678 | ||
| 679 | def directories_of(dir) | |
| 680 | Dir.open(dir) {|d| | |
| 681 | return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT | |
| 682 | } | |
| 683 | end | |
| 684 | ||
| 685 | end | |
| 686 | ||
| 687 | ||
| 688 | # This module requires: #srcdir_root, #objdir_root, #relpath | |
| 689 | module HookScriptAPI | |
| 690 | ||
| 691 | def get_config(key) | |
| 692 | @config[key] | |
| 693 | end | |
| 694 | ||
| 695 | alias config get_config | |
| 696 | ||
| 697 | # obsolete: use metaconfig to change configuration | |
| 698 | def set_config(key, val) | |
| 699 | @config[key] = val | |
| 700 | end | |
| 701 | ||
| 702 | # | |
| 703 | # srcdir/objdir (works only in the package directory) | |
| 704 | # | |
| 705 | ||
| 706 | def curr_srcdir | |
| 707 | "#{srcdir_root()}/#{relpath()}" | |
| 708 | end | |
| 709 | ||
| 710 | def curr_objdir | |
| 711 | "#{objdir_root()}/#{relpath()}" | |
| 712 | end | |
| 713 | ||
| 714 | def srcfile(path) | |
| 715 | "#{curr_srcdir()}/#{path}" | |
| 716 | end | |
| 717 | ||
| 718 | def srcexist?(path) | |
| 719 | File.exist?(srcfile(path)) | |
| 720 | end | |
| 721 | ||
| 722 | def srcdirectory?(path) | |
| 723 | File.dir?(srcfile(path)) | |
| 724 | end | |
| 725 | ||
| 726 | def srcfile?(path) | |
| 727 | File.file?(srcfile(path)) | |
| 728 | end | |
| 729 | ||
| 730 | def srcentries(path = '.') | |
| 731 | Dir.open("#{curr_srcdir()}/#{path}") {|d| | |
| 732 | return d.to_a - %w(. ..) | |
| 733 | } | |
| 734 | end | |
| 735 | ||
| 736 | def srcfiles(path = '.') | |
| 737 | srcentries(path).select {|fname| | |
| 738 | File.file?(File.join(curr_srcdir(), path, fname)) | |
| 739 | } | |
| 740 | end | |
| 741 | ||
| 742 | def srcdirectories(path = '.') | |
| 743 | srcentries(path).select {|fname| | |
| 744 | File.dir?(File.join(curr_srcdir(), path, fname)) | |
| 745 | } | |
| 746 | end | |
| 747 | ||
| 748 | end | |
| 749 | ||
| 750 | ||
| 751 | class ToplevelInstaller | |
| 752 | ||
| 753 | Version = '3.4.1' | |
| 754 | Copyright = 'Copyright (c) 2000-2005 Minero Aoki' | |
| 755 | ||
| 756 | TASKS = [ | |
| 757 | [ 'all', 'do config, setup, then install' ], | |
| 758 | [ 'config', 'saves your configurations' ], | |
| 759 | [ 'show', 'shows current configuration' ], | |
| 760 | [ 'setup', 'compiles ruby extentions and others' ], | |
| 761 | [ 'install', 'installs files' ], | |
| 762 | [ 'test', 'run all tests in test/' ], | |
| 763 | [ 'clean', "does `make clean' for each extention" ], | |
| 764 | [ 'distclean',"does `make distclean' for each extention" ] | |
| 765 | ] | |
| 766 | ||
| 767 | def ToplevelInstaller.invoke | |
| 768 | config = ConfigTable.new(load_rbconfig()) | |
| 769 | config.load_standard_entries | |
| 770 | config.load_multipackage_entries if multipackage? | |
| 771 | config.fixup | |
| 772 | klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) | |
| 773 | klass.new(File.dirname($0), config).invoke | |
| 774 | end | |
| 775 | ||
| 776 | def ToplevelInstaller.multipackage? | |
| 777 | File.dir?(File.dirname($0) + '/packages') | |
| 778 | end | |
| 779 | ||
| 780 | def ToplevelInstaller.load_rbconfig | |
| 781 | if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } | |
| 782 | ARGV.delete(arg) | |
| 783 | load File.expand_path(arg.split(/=/, 2)[1]) | |
| 784 | $".push 'rbconfig.rb' | |
| 785 | else | |
| 786 | require 'rbconfig' | |
| 787 | end | |
| 788 | ::Config::CONFIG | |
| 789 | end | |
| 790 | ||
| 791 | def initialize(ardir_root, config) | |
| 792 | @ardir = File.expand_path(ardir_root) | |
| 793 | @config = config | |
| 794 | # cache | |
| 795 | @valid_task_re = nil | |
| 796 | end | |
| 797 | ||
| 798 | def config(key) | |
| 799 | @config[key] | |
| 800 | end | |
| 801 | ||
| 802 | def inspect | |
| 803 | "#<#{self.class} #{__id__()}>" | |
| 804 | end | |
| 805 | ||
| 806 | def invoke | |
| 807 | run_metaconfigs | |
| 808 | case task = parsearg_global() | |
| 809 | when nil, 'all' | |
| 810 | parsearg_config | |
| 811 | init_installers | |
| 812 | exec_config | |
| 813 | exec_setup | |
| 814 | exec_install | |
| 815 | else | |
| 816 | case task | |
| 817 | when 'config', 'test' | |
| 818 | ; | |
| 819 | when 'clean', 'distclean' | |
| 820 | @config.load_savefile if File.exist?(@config.savefile) | |
| 821 | else | |
| 822 | @config.load_savefile | |
| 823 | end | |
| 824 | __send__ "parsearg_#{task}" | |
| 825 | init_installers | |
| 826 | __send__ "exec_#{task}" | |
| 827 | end | |
| 828 | end | |
| 829 | ||
| 830 | def run_metaconfigs | |
| 831 | @config.load_script "#{@ardir}/metaconfig" | |
| 832 | end | |
| 833 | ||
| 834 | def init_installers | |
| 835 | @installer = Installer.new(@config, @ardir, File.expand_path('.')) | |
| 836 | end | |
| 837 | ||
| 838 | # | |
| 839 | # Hook Script API bases | |
| 840 | # | |
| 841 | ||
| 842 | def srcdir_root | |
| 843 | @ardir | |
| 844 | end | |
| 845 | ||
| 846 | def objdir_root | |
| 847 | '.' | |
| 848 | end | |
| 849 | ||
| 850 | def relpath | |
| 851 | '.' | |
| 852 | end | |
| 853 | ||
| 854 | # | |
| 855 | # Option Parsing | |
| 856 | # | |
| 857 | ||
| 858 | def parsearg_global | |
| 859 | while arg = ARGV.shift | |
| 860 | case arg | |
| 861 | when /\A\w+\z/ | |
| 862 | setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) | |
| 863 | return arg | |
| 864 | when '-q', '--quiet' | |
| 865 | @config.verbose = false | |
| 866 | when '--verbose' | |
| 867 | @config.verbose = true | |
| 868 | when '--help' | |
| 869 | print_usage $stdout | |
| 870 | exit 0 | |
| 871 | when '--version' | |
| 872 | puts "#{File.basename($0)} version #{Version}" | |
| 873 | exit 0 | |
| 874 | when '--copyright' | |
| 875 | puts Copyright | |
| 876 | exit 0 | |
| 877 | else | |
| 878 | setup_rb_error "unknown global option '#{arg}'" | |
| 879 | end | |
| 880 | end | |
| 881 | nil | |
| 882 | end | |
| 883 | ||
| 884 | def valid_task?(t) | |
| 885 | valid_task_re() =~ t | |
| 886 | end | |
| 887 | ||
| 888 | def valid_task_re | |
| 889 | @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ | |
| 890 | end | |
| 891 | ||
| 892 | def parsearg_no_options | |
| 893 | unless ARGV.empty? | |
| 894 | task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) | |
| 895 | setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" | |
| 896 | end | |
| 897 | end | |
| 898 | ||
| 899 | alias parsearg_show parsearg_no_options | |
| 900 | alias parsearg_setup parsearg_no_options | |
| 901 | alias parsearg_test parsearg_no_options | |
| 902 | alias parsearg_clean parsearg_no_options | |
| 903 | alias parsearg_distclean parsearg_no_options | |
| 904 | ||
| 905 | def parsearg_config | |
| 906 | evalopt = [] | |
| 907 | set = [] | |
| 908 | @config.config_opt = [] | |
| 909 | while i = ARGV.shift | |
| 910 | if /\A--?\z/ =~ i | |
| 911 | @config.config_opt = ARGV.dup | |
| 912 | break | |
| 913 | end | |
| 914 | name, value = *@config.parse_opt(i) | |
| 915 | if @config.value_config?(name) | |
| 916 | @config[name] = value | |
| 917 | else | |
| 918 | evalopt.push [name, value] | |
| 919 | end | |