Guest User

Untitled

a guest
Jun 21st, 2018
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.56 KB | None | 0 0
  1. unless File.respond_to?(:read) # Ruby 1.6
  2. def File.read(fname)
  3. open(fname) {|f| return f.read }
  4. end
  5. end
  6.  
  7. unless Errno.const_defined?(:ENOTEMPTY) # Windows?
  8. module Errno
  9. class ENOTEMPTY
  10. # We do not raise this exception, implementation is not needed.
  11. end
  12. end
  13. end
  14.  
  15. def File.binread(fname)
  16. open(fname, 'rb') {|f|
  17. return f.read
  18. }
  19. end
  20.  
  21.  
  22. # ================================================================== #
  23. # for corrupted Windows' stat(2)
  24. # ================================================================== #
  25. def File.dir?(path)
  26. File.directory?((path[-1,1] == '/') ? path : path + '/')
  27. end
  28.  
  29.  
  30. # ================================================================== #
  31. # ConfigTable.new
  32. # ================================================================== #
  33. class ConfigTable
  34.  
  35. include Enumerable
  36.  
  37. def initialize(rbconfig)
  38. @rbconfig = rbconfig
  39. @items = []
  40. @table = {}
  41. # options
  42. @install_prefix = nil
  43. @config_opt = nil
  44. @verbose = true
  45. @no_harm = false
  46. end
  47.  
  48. attr_accessor :install_prefix
  49. attr_accessor :config_opt
  50.  
  51. attr_writer :verbose
  52.  
  53. def verbose?
  54. @verbose
  55. end
  56.  
  57. attr_writer :no_harm
  58.  
  59. def no_harm?
  60. @no_harm
  61. end
  62.  
  63. def [](key)
  64. lookup(key).resolve(self)
  65. end
  66.  
  67. def []=(key, val)
  68. lookup(key).set val
  69. end
  70.  
  71. def names
  72. @items.map {|i| i.name }
  73. end
  74.  
  75. def each(&block)
  76. @items.each(&block)
  77. end
  78.  
  79. def key?(name)
  80. @table.key?(name)
  81. end
  82.  
  83. def lookup(name)
  84. @table[name] or setup_rb_error "no such config item: #{name}"
  85. end
  86.  
  87. def add(item)
  88. @items.push item
  89. @table[item.name] = item
  90. end
  91.  
  92. def remove(name)
  93. item = lookup(name)
  94. @items.delete_if {|i| i.name == name }
  95. @table.delete_if {|name, i| i.name == name }
  96. item
  97. end
  98.  
  99. def load_script(path, inst = nil)
  100. if File.file?(path)
  101. MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
  102. end
  103. end
  104.  
  105. def savefile
  106. '.config'
  107. end
  108.  
  109. def load_savefile
  110. begin
  111. File.foreach(savefile()) do |line|
  112. k, v = *line.split(/=/, 2)
  113. self[k] = v.strip
  114. end
  115. rescue Errno::ENOENT
  116. setup_rb_error $!.message + "\n#{File.basename($0)} config first"
  117. end
  118. end
  119.  
  120. def save
  121. @items.each {|i| i.value }
  122. File.open(savefile(), 'w') {|f|
  123. @items.each do |i|
  124. f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
  125. end
  126. }
  127. end
  128.  
  129. def load_standard_entries
  130. standard_entries(@rbconfig).each do |ent|
  131. add ent
  132. end
  133. end
  134.  
  135. def standard_entries(rbconfig)
  136. c = rbconfig
  137.  
  138. rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
  139.  
  140. major = c['MAJOR'].to_i
  141. minor = c['MINOR'].to_i
  142. teeny = c['TEENY'].to_i
  143. version = "#{major}.#{minor}"
  144.  
  145. # ruby ver. >= 1.4.4?
  146. newpath_p = ((major >= 2) or
  147. ((major == 1) and
  148. ((minor >= 5) or
  149. ((minor == 4) and (teeny >= 4)))))
  150.  
  151. if c['rubylibdir']
  152. # V > 1.6.3
  153. libruby = "#{c['prefix']}/lib/ruby"
  154. librubyver = c['rubylibdir']
  155. librubyverarch = c['archdir']
  156. siteruby = c['sitedir']
  157. siterubyver = c['sitelibdir']
  158. siterubyverarch = c['sitearchdir']
  159. elsif newpath_p
  160. # 1.4.4 <= V <= 1.6.3
  161. libruby = "#{c['prefix']}/lib/ruby"
  162. librubyver = "#{c['prefix']}/lib/ruby/#{version}"
  163. librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
  164. siteruby = c['sitedir']
  165. siterubyver = "$siteruby/#{version}"
  166. siterubyverarch = "$siterubyver/#{c['arch']}"
  167. else
  168. # V < 1.4.4
  169. libruby = "#{c['prefix']}/lib/ruby"
  170. librubyver = "#{c['prefix']}/lib/ruby/#{version}"
  171. librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
  172. siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
  173. siterubyver = siteruby
  174. siterubyverarch = "$siterubyver/#{c['arch']}"
  175. end
  176. parameterize = lambda {|path|
  177. path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
  178. }
  179.  
  180. if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
  181. makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
  182. else
  183. makeprog = 'make'
  184. end
  185.  
  186. [
  187. ExecItem.new('installdirs', 'std/site/home',
  188. 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
  189. {|val, table|
  190. case val
  191. when 'std'
  192. table['rbdir'] = '$librubyver'
  193. table['sodir'] = '$librubyverarch'
  194. when 'site'
  195. table['rbdir'] = '$siterubyver'
  196. table['sodir'] = '$siterubyverarch'
  197. when 'home'
  198. setup_rb_error '$HOME was not set' unless ENV['HOME']
  199. table['prefix'] = ENV['HOME']
  200. table['rbdir'] = '$libdir/ruby'
  201. table['sodir'] = '$libdir/ruby'
  202. end
  203. },
  204. PathItem.new('prefix', 'path', c['prefix'],
  205. 'path prefix of target environment'),
  206. PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
  207. 'the directory for commands'),
  208. PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
  209. 'the directory for libraries'),
  210. PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
  211. 'the directory for shared data'),
  212. PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
  213. 'the directory for man pages'),
  214. PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
  215. 'the directory for system configuration files'),
  216. PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
  217. 'the directory for local state data'),
  218. PathItem.new('libruby', 'path', libruby,
  219. 'the directory for ruby libraries'),
  220. PathItem.new('librubyver', 'path', librubyver,
  221. 'the directory for standard ruby libraries'),
  222. PathItem.new('librubyverarch', 'path', librubyverarch,
  223. 'the directory for standard ruby extensions'),
  224. PathItem.new('siteruby', 'path', siteruby,
  225. 'the directory for version-independent aux ruby libraries'),
  226. PathItem.new('siterubyver', 'path', siterubyver,
  227. 'the directory for aux ruby libraries'),
  228. PathItem.new('siterubyverarch', 'path', siterubyverarch,
  229. 'the directory for aux ruby binaries'),
  230. PathItem.new('rbdir', 'path', '$siterubyver',
  231. 'the directory for ruby scripts'),
  232. PathItem.new('sodir', 'path', '$siterubyverarch',
  233. 'the directory for ruby extentions'),
  234. PathItem.new('rubypath', 'path', rubypath,
  235. 'the path to set to #! line'),
  236. ProgramItem.new('rubyprog', 'name', rubypath,
  237. 'the ruby program using for installation'),
  238. ProgramItem.new('makeprog', 'name', makeprog,
  239. 'the make program to compile ruby extentions'),
  240. SelectItem.new('shebang', 'all/ruby/never', 'ruby',
  241. 'shebang line (#!) editing mode'),
  242. BoolItem.new('without-ext', 'yes/no', 'no',
  243. 'does not compile/install ruby extentions')
  244. ]
  245. end
  246. private :standard_entries
  247.  
  248. def load_multipackage_entries
  249. multipackage_entries().each do |ent|
  250. add ent
  251. end
  252. end
  253.  
  254. def multipackage_entries
  255. [
  256. PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
  257. 'package names that you want to install'),
  258. PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
  259. 'package names that you do not want to install')
  260. ]
  261. end
  262. private :multipackage_entries
  263.  
  264. ALIASES = {
  265. 'std-ruby' => 'librubyver',
  266. 'stdruby' => 'librubyver',
  267. 'rubylibdir' => 'librubyver',
  268. 'archdir' => 'librubyverarch',
  269. 'site-ruby-common' => 'siteruby', # For backward compatibility
  270. 'site-ruby' => 'siterubyver', # For backward compatibility
  271. 'bin-dir' => 'bindir',
  272. 'bin-dir' => 'bindir',
  273. 'rb-dir' => 'rbdir',
  274. 'so-dir' => 'sodir',
  275. 'data-dir' => 'datadir',
  276. 'ruby-path' => 'rubypath',
  277. 'ruby-prog' => 'rubyprog',
  278. 'ruby' => 'rubyprog',
  279. 'make-prog' => 'makeprog',
  280. 'make' => 'makeprog'
  281. }
  282. # ================================================================ #
  283. #
  284. # ================================================================ #
  285. def fixup
  286. ALIASES.each do |ali, name|
  287. @table[ali] = @table[name]
  288. end
  289. @items.freeze
  290. @table.freeze
  291. @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
  292. end
  293.  
  294. def parse_opt(opt)
  295. m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
  296. m.to_a[1,2]
  297. end
  298.  
  299. def dllext
  300. @rbconfig['DLEXT']
  301. end
  302.  
  303. def value_config?(name)
  304. lookup(name).value?
  305. end
  306.  
  307. # ================================================================== #
  308. #
  309. # ================================================================== #
  310. class Item
  311.  
  312. def initialize(name, template, default, desc)
  313. @name = name.freeze
  314. @template = template
  315. @value = default
  316. @default = default
  317. @description = desc
  318. end
  319.  
  320. attr_reader :name
  321. attr_reader :description
  322.  
  323. attr_accessor :default
  324. alias help_default default
  325.  
  326. def help_opt
  327. "--#{@name}=#{@template}"
  328. end
  329.  
  330. def value?
  331. true
  332. end
  333.  
  334. def value
  335. @value
  336. end
  337.  
  338. def resolve(table)
  339. @value.gsub(%r<\$([^/]+)>) { table[$1] }
  340. end
  341.  
  342. def set(val)
  343. @value = check(val)
  344. end
  345.  
  346. private
  347.  
  348. def check(val)
  349. setup_rb_error "config: --#{name} requires argument" unless val
  350. val
  351. end
  352. end
  353.  
  354.  
  355. # ================================================================== #
  356. #
  357. # ================================================================== #
  358. class BoolItem < Item
  359. def config_type
  360. 'bool'
  361. end
  362. def help_opt
  363. "--#{@name}"
  364. end
  365.  
  366. private
  367. def check(val)
  368. return 'yes' unless val
  369. case val
  370. when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
  371. when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
  372. else
  373. setup_rb_error "config: --#{@name} accepts only yes/no for argument"
  374. end
  375. end
  376. end
  377.  
  378. class PathItem < Item
  379. def config_type
  380. 'path'
  381. end
  382.  
  383. private
  384.  
  385. def check(path)
  386. setup_rb_error "config: --#{@name} requires argument" unless path
  387. path[0,1] == '$' ? path : File.expand_path(path)
  388. end
  389. end
  390. # ================================================================ #
  391. #
  392. # ================================================================ #
  393. class ProgramItem < Item
  394. def config_type
  395. 'program'
  396. end
  397. end
  398.  
  399. class SelectItem < Item
  400. def initialize(name, selection, default, desc)
  401. super
  402. @ok = selection.split('/')
  403. end
  404.  
  405. def config_type
  406. 'select'
  407. end
  408.  
  409. private
  410.  
  411. def check(val)
  412. unless @ok.include?(val.strip)
  413. setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
  414. end
  415. val.strip
  416. end
  417. end
  418. # ================================================================ #
  419. #
  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
  920. set.push name
  921. end
  922. evalopt.each do |name, value|
  923. @config.lookup(name).evaluate value, @config
  924. end
  925. # Check if configuration is valid
  926. set.each do |n|
  927. @config[n] if @config.value_config?(n)
  928. end
  929. end
  930.  
  931. def parsearg_install
  932. @config.no_harm = false
  933. @config.install_prefix = ''
  934. while a = ARGV.shift
  935. case a
  936. when '--no-harm'
  937. @config.no_harm = true
  938. when /\A--prefix=/
  939. path = a.split(/=/, 2)[1]
  940. path = File.expand_path(path) unless path[0,1] == '/'
  941. @config.install_prefix = path
  942. else
  943. setup_rb_error "install: unknown option #{a}"
  944. end
  945. end
  946. end
  947.  
  948. def print_usage(out)
  949. out.puts 'Typical Installation Procedure:'
  950. out.puts " $ ruby #{File.basename $0} config"
  951. out.puts " $ ruby #{File.basename $0} setup"
  952. out.puts " # ruby #{File.basename $0} install (may require root privilege)"
  953. out.puts
  954. out.puts 'Detailed Usage:'
  955. out.puts " ruby #{File.basename $0} <global option>"
  956. out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
  957.  
  958. fmt = " %-24s %s\n"
  959. out.puts
  960. out.puts 'Global options:'
  961. out.printf fmt, '-q,--quiet', 'suppress message outputs'
  962. out.printf fmt, ' --verbose', 'output messages verbosely'
  963. out.printf fmt, ' --help', 'print this message'
  964. out.printf fmt, ' --version', 'print version and quit'
  965. out.printf fmt, ' --copyright', 'print copyright and quit'
  966. out.puts
  967. out.puts 'Tasks:'
  968. TASKS.each do |name, desc|
  969. out.printf fmt, name, desc
  970. end
  971.  
  972. fmt = " %-24s %s [%s]\n"
  973. out.puts
  974. out.puts 'Options for CONFIG or ALL:'
  975. @config.each do |item|
  976. out.printf fmt, item.help_opt, item.description, item.help_default
  977. end
  978. out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
  979. out.puts
  980. out.puts 'Options for INSTALL:'
  981. out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
  982. out.printf fmt, '--prefix=path', 'install path prefix', ''
  983. out.puts
  984. end
  985.  
  986. #
  987. # Task Handlers
  988. #
  989.  
  990. def exec_config
  991. @installer.exec_config
  992. @config.save # must be final
  993. end
  994.  
  995. def exec_setup
  996. @installer.exec_setup
  997. end
  998.  
  999. def exec_install
  1000. @installer.exec_install
  1001. end
  1002.  
  1003. def exec_test
  1004. @installer.exec_test
  1005. end
  1006.  
  1007. def exec_show
  1008. @config.each do |i|
  1009. printf "%-20s %s\n", i.name, i.value if i.value?
  1010. end
  1011. end
  1012.  
  1013. def exec_clean
  1014. @installer.exec_clean
  1015. end
  1016.  
  1017. def exec_distclean
  1018. @installer.exec_distclean
  1019. end
  1020.  
  1021. end # class ToplevelInstaller
  1022.  
  1023.  
  1024. class ToplevelInstallerMulti < ToplevelInstaller
  1025.  
  1026. include FileOperations
  1027.  
  1028. def initialize(ardir_root, config)
  1029. super
  1030. @packages = directories_of("#{@ardir}/packages")
  1031. raise 'no package exists' if @packages.empty?
  1032. @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
  1033. end
  1034.  
  1035. def run_metaconfigs
  1036. @config.load_script "#{@ardir}/metaconfig", self
  1037. @packages.each do |name|
  1038. @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
  1039. end
  1040. end
  1041.  
  1042. attr_reader :packages
  1043.  
  1044. def packages=(list)
  1045. raise 'package list is empty' if list.empty?
  1046. list.each do |name|
  1047. raise "directory packages/#{name} does not exist"\
  1048. unless File.dir?("#{@ardir}/packages/#{name}")
  1049. end
  1050. @packages = list
  1051. end
  1052.  
  1053. def init_installers
  1054. @installers = {}
  1055. @packages.each do |pack|
  1056. @installers[pack] = Installer.new(@config,
  1057. "#{@ardir}/packages/#{pack}",
  1058. "packages/#{pack}")
  1059. end
  1060. with = extract_selection(config('with'))
  1061. without = extract_selection(config('without'))
  1062. @selected = @installers.keys.select {|name|
  1063. (with.empty? or with.include?(name)) \
  1064. and not without.include?(name)
  1065. }
  1066. end
  1067.  
  1068. def extract_selection(list)
  1069. a = list.split(/,/)
  1070. a.each do |name|
  1071. setup_rb_error "no such package: #{name}" unless @installers.key?(name)
  1072. end
  1073. a
  1074. end
  1075.  
  1076. def print_usage(f)
  1077. super
  1078. f.puts 'Inluded packages:'
  1079. f.puts ' ' + @packages.sort.join(' ')
  1080. f.puts
  1081. end
  1082.  
  1083. #
  1084. # Task Handlers
  1085. #
  1086.  
  1087. def exec_config
  1088. run_hook 'pre-config'
  1089. each_selected_installers {|inst| inst.exec_config }
  1090. run_hook 'post-config'
  1091. @config.save # must be final
  1092. end
  1093.  
  1094. def exec_setup
  1095. run_hook 'pre-setup'
  1096. each_selected_installers {|inst| inst.exec_setup }
  1097. run_hook 'post-setup'
  1098. end
  1099.  
  1100. def exec_install
  1101. run_hook 'pre-install'
  1102. each_selected_installers {|inst| inst.exec_install }
  1103. run_hook 'post-install'
  1104. end
  1105.  
  1106. def exec_test
  1107. run_hook 'pre-test'
  1108. each_selected_installers {|inst| inst.exec_test }
  1109. run_hook 'post-test'
  1110. end
  1111.  
  1112. def exec_clean
  1113. rm_f @config.savefile
  1114. run_hook 'pre-clean'
  1115. each_selected_installers {|inst| inst.exec_clean }
  1116. run_hook 'post-clean'
  1117. end
  1118.  
  1119. def exec_distclean
  1120. rm_f @config.savefile
  1121. run_hook 'pre-distclean'
  1122. each_selected_installers {|inst| inst.exec_distclean }
  1123. run_hook 'post-distclean'
  1124. end
  1125.  
  1126. #
  1127. # lib
  1128. #
  1129.  
  1130. def each_selected_installers
  1131. Dir.mkdir 'packages' unless File.dir?('packages')
  1132. @selected.each do |pack|
  1133. $stderr.puts "Processing the package `#{pack}' ..." if verbose?
  1134. Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
  1135. Dir.chdir "packages/#{pack}"
  1136. yield @installers[pack]
  1137. Dir.chdir '../..'
  1138. end
  1139. end
  1140.  
  1141. def run_hook(id)
  1142. @root_installer.run_hook id
  1143. end
  1144.  
  1145. # module FileOperations requires this
  1146. def verbose?
  1147. @config.verbose?
  1148. end
  1149.  
  1150. # module FileOperations requires this
  1151. def no_harm?
  1152. @config.no_harm?
  1153. end
  1154.  
  1155. end # class ToplevelInstallerMulti
  1156.  
  1157.  
  1158. class Installer
  1159.  
  1160. FILETYPES = %w( bin lib ext data conf man )
  1161.  
  1162. include FileOperations
  1163. include HookScriptAPI
  1164.  
  1165. def initialize(config, srcroot, objroot)
  1166. @config = config
  1167. @srcdir = File.expand_path(srcroot)
  1168. @objdir = File.expand_path(objroot)
  1169. @currdir = '.'
  1170. end
  1171.  
  1172. def inspect
  1173. "#<#{self.class} #{File.basename(@srcdir)}>"
  1174. end
  1175.  
  1176. def noop(rel)
  1177. end
  1178.  
  1179. #
  1180. # Hook Script API base methods
  1181. #
  1182.  
  1183. def srcdir_root
  1184. @srcdir
  1185. end
  1186.  
  1187. def objdir_root
  1188. @objdir
  1189. end
  1190.  
  1191. def relpath
  1192. @currdir
  1193. end
  1194.  
  1195. #
  1196. # Config Access
  1197. #
  1198.  
  1199. # module FileOperations requires this
  1200. def verbose?
  1201. @config.verbose?
  1202. end
  1203.  
  1204. # module FileOperations requires this
  1205. def no_harm?
  1206. @config.no_harm?
  1207. end
  1208.  
  1209. def verbose_off
  1210. begin
  1211. save, @config.verbose = @config.verbose?, false
  1212. yield
  1213. ensure
  1214. @config.verbose = save
  1215. end
  1216. end
  1217.  
  1218. #
  1219. # TASK config
  1220. #
  1221.  
  1222. def exec_config
  1223. exec_task_traverse 'config'
  1224. end
  1225.  
  1226. alias config_dir_bin noop
  1227. alias config_dir_lib noop
  1228.  
  1229. def config_dir_ext(rel)
  1230. extconf if extdir?(curr_srcdir())
  1231. end
  1232.  
  1233. alias config_dir_data noop
  1234. alias config_dir_conf noop
  1235. alias config_dir_man noop
  1236.  
  1237. def extconf
  1238. ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
  1239. end
  1240.  
  1241. #
  1242. # TASK setup
  1243. #
  1244.  
  1245. def exec_setup
  1246. exec_task_traverse 'setup'
  1247. end
  1248.  
  1249. def setup_dir_bin(rel)
  1250. files_of(curr_srcdir()).each do |fname|
  1251. update_shebang_line "#{curr_srcdir()}/#{fname}"
  1252. end
  1253. end
  1254.  
  1255. alias setup_dir_lib noop
  1256.  
  1257. def setup_dir_ext(rel)
  1258. make if extdir?(curr_srcdir())
  1259. end
  1260.  
  1261. alias setup_dir_data noop
  1262. alias setup_dir_conf noop
  1263. alias setup_dir_man noop
  1264.  
  1265. def update_shebang_line(path)
  1266. return if no_harm?
  1267. return if config('shebang') == 'never'
  1268. old = Shebang.load(path)
  1269. if old
  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
  1271. new = new_shebang(old)
  1272. return if new.to_s == old.to_s
  1273. else
  1274. return unless config('shebang') == 'all'
  1275. new = Shebang.new(config('rubypath'))
  1276. end
  1277. $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
  1278. open_atomic_writer(path) {|output|
  1279. File.open(path, 'rb') {|f|
  1280. f.gets if old # discard
  1281. output.puts new.to_s
  1282. output.print f.read
  1283. }
  1284. }
  1285. end
  1286.  
  1287. def new_shebang(old)
  1288. if /\Aruby/ =~ File.basename(old.cmd)
  1289. Shebang.new(config('rubypath'), old.args)
  1290. elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
  1291. Shebang.new(config('rubypath'), old.args[1..-1])
  1292. else
  1293. return old unless config('shebang') == 'all'
  1294. Shebang.new(config('rubypath'))
  1295. end
  1296. end
  1297.  
  1298. def open_atomic_writer(path, &block)
  1299. tmpfile = File.basename(path) + '.tmp'
  1300. begin
  1301. File.open(tmpfile, 'wb', &block)
  1302. File.rename tmpfile, File.basename(path)
  1303. ensure
  1304. File.unlink tmpfile if File.exist?(tmpfile)
  1305. end
  1306. end
  1307.  
  1308. class Shebang
  1309. def Shebang.load(path)
  1310. line = nil
  1311. File.open(path) {|f|
  1312. line = f.gets
  1313. }
  1314. return nil unless /\A#!/ =~ line
  1315. parse(line)
  1316. end
  1317.  
  1318. def Shebang.parse(line)
  1319. cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
  1320. new(cmd, args)
  1321. end
  1322.  
  1323. def initialize(cmd, args = [])
  1324. @cmd = cmd
  1325. @args = args
  1326. end
  1327.  
  1328. attr_reader :cmd
  1329. attr_reader :args
  1330.  
  1331. def to_s
  1332. "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
  1333. end
  1334. end
  1335.  
  1336. #
  1337. # TASK install
  1338. #
  1339.  
  1340. def exec_install
  1341. rm_f 'InstalledFiles'
  1342. exec_task_traverse 'install'
  1343. end
  1344.  
  1345. def install_dir_bin(rel)
  1346. install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
  1347. end
  1348.  
  1349. def install_dir_lib(rel)
  1350. install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
  1351. end
  1352.  
  1353. def install_dir_ext(rel)
  1354. return unless extdir?(curr_srcdir())
  1355. install_files rubyextentions('.'),
  1356. "#{config('sodir')}/#{File.dirname(rel)}",
  1357. 0555
  1358. end
  1359.  
  1360. def install_dir_data(rel)
  1361. install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
  1362. end
  1363.  
  1364. def install_dir_conf(rel)
  1365. # FIXME: should not remove current config files
  1366. # (rename previous file to .old/.org)
  1367. install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
  1368. end
  1369.  
  1370. def install_dir_man(rel)
  1371. install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
  1372. end
  1373.  
  1374. def install_files(list, dest, mode)
  1375. mkdir_p dest, @config.install_prefix
  1376. list.each do |fname|
  1377. install fname, dest, mode, @config.install_prefix
  1378. end
  1379. end
  1380.  
  1381. def libfiles
  1382. glob_reject(%w(*.y *.output), targetfiles())
  1383. end
  1384.  
  1385. def rubyextentions(dir)
  1386. ents = glob_select("*.#{@config.dllext}", targetfiles())
  1387. if ents.empty?
  1388. setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
  1389. end
  1390. ents
  1391. end
  1392.  
  1393. def targetfiles
  1394. mapdir(existfiles() - hookfiles())
  1395. end
  1396.  
  1397. def mapdir(ents)
  1398. ents.map {|ent|
  1399. if File.exist?(ent)
  1400. then ent # objdir
  1401. else "#{curr_srcdir()}/#{ent}" # srcdir
  1402. end
  1403. }
  1404. end
  1405.  
  1406. # picked up many entries from cvs-1.11.1/src/ignore.c
  1407. JUNK_FILES = %w(
  1408. core RCSLOG tags TAGS .make.state
  1409. .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
  1410. *~ *.old *.bak *.BAK *.orig *.rej _$* *$
  1411.  
  1412. *.org *.in .*
  1413. )
  1414.  
  1415. def existfiles
  1416. glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
  1417. end
  1418.  
  1419. def hookfiles
  1420. %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
  1421. %w( config setup install clean ).map {|t| sprintf(fmt, t) }
  1422. }.flatten
  1423. end
  1424.  
  1425. def glob_select(pat, ents)
  1426. re = globs2re([pat])
  1427. ents.select {|ent| re =~ ent }
  1428. end
  1429.  
  1430. def glob_reject(pats, ents)
  1431. re = globs2re(pats)
  1432. ents.reject {|ent| re =~ ent }
  1433. end
  1434.  
  1435. GLOB2REGEX = {
  1436. '.' => '\.',
  1437. '$' => '\$',
  1438. '#' => '\#',
  1439. '*' => '.*'
  1440. }
  1441.  
  1442. def globs2re(pats)
  1443. /\A(?:#{
  1444. pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
  1445. })\z/
  1446. end
  1447.  
  1448. #
  1449. # TASK test
  1450. #
  1451.  
  1452. TESTDIR = 'test'
  1453.  
  1454. def exec_test
  1455. unless File.directory?('test')
  1456. $stderr.puts 'no test in this package' if verbose?
  1457. return
  1458. end
  1459. $stderr.puts 'Running tests...' if verbose?
  1460. begin
  1461. require 'test/unit'
  1462. rescue LoadError
  1463. setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
  1464. end
  1465. runner = Test::Unit::AutoRunner.new(true)
  1466. runner.to_run << TESTDIR
  1467. runner.run
  1468. end
  1469.  
  1470. #
  1471. # TASK clean
  1472. #
  1473.  
  1474. def exec_clean
  1475. exec_task_traverse 'clean'
  1476. rm_f @config.savefile
  1477. rm_f 'InstalledFiles'
  1478. end
  1479.  
  1480. alias clean_dir_bin noop
  1481. alias clean_dir_lib noop
  1482. alias clean_dir_data noop
  1483. alias clean_dir_conf noop
  1484. alias clean_dir_man noop
  1485.  
  1486. def clean_dir_ext(rel)
  1487. return unless extdir?(curr_srcdir())
  1488. make 'clean' if File.file?('Makefile')
  1489. end
  1490.  
  1491. #
  1492. # TASK distclean
  1493. #
  1494.  
  1495. def exec_distclean
  1496. exec_task_traverse 'distclean'
  1497. rm_f @config.savefile
  1498. rm_f 'InstalledFiles'
  1499. end
  1500.  
  1501. alias distclean_dir_bin noop
  1502. alias distclean_dir_lib noop
  1503.  
  1504. def distclean_dir_ext(rel)
  1505. return unless extdir?(curr_srcdir())
  1506. make 'distclean' if File.file?('Makefile')
  1507. end
  1508.  
  1509. alias distclean_dir_data noop
  1510. alias distclean_dir_conf noop
  1511. alias distclean_dir_man noop
  1512.  
  1513. #
  1514. # Traversing
  1515. #
  1516.  
  1517. def exec_task_traverse(task)
  1518. run_hook "pre-#{task}"
  1519. FILETYPES.each do |type|
  1520. if type == 'ext' and config('without-ext') == 'yes'
  1521. $stderr.puts 'skipping ext/* by user option' if verbose?
  1522. next
  1523. end
  1524. traverse task, type, "#{task}_dir_#{type}"
  1525. end
  1526. run_hook "post-#{task}"
  1527. end
  1528.  
  1529. def traverse(task, rel, mid)
  1530. dive_into(rel) {
  1531. run_hook "pre-#{task}"
  1532. __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
  1533. directories_of(curr_srcdir()).each do |d|
  1534. traverse task, "#{rel}/#{d}", mid
  1535. end
  1536. run_hook "post-#{task}"
  1537. }
  1538. end
  1539.  
  1540. def dive_into(rel)
  1541. return unless File.dir?("#{@srcdir}/#{rel}")
  1542.  
  1543. dir = File.basename(rel)
  1544. Dir.mkdir dir unless File.dir?(dir)
  1545. prevdir = Dir.pwd
  1546. Dir.chdir dir
  1547. $stderr.puts '---> ' + rel if verbose?
  1548. @currdir = rel
  1549. yield
  1550. Dir.chdir prevdir
  1551. $stderr.puts '<--- ' + rel if verbose?
  1552. @currdir = File.dirname(rel)
  1553. end
  1554.  
  1555. def run_hook(id)
  1556. path = [ "#{curr_srcdir()}/#{id}",
  1557. "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
  1558. return unless path
  1559. begin
  1560. instance_eval File.read(path), path, 1
  1561. rescue
  1562. raise if $DEBUG
  1563. setup_rb_error "hook #{path} failed:\n" + $!.message
  1564. end
  1565. end
  1566.  
  1567. end # class Installer
  1568.  
  1569.  
  1570. class SetupError < StandardError; end
  1571.  
  1572. def setup_rb_error(msg)
  1573. raise SetupError, msg
  1574. end
  1575.  
  1576. if $0 == __FILE__
  1577. begin
  1578. ToplevelInstaller.invoke
  1579. rescue SetupError
  1580. raise if $DEBUG
  1581. $stderr.puts $!.message
  1582. $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
  1583. exit 1
  1584. end
  1585. end
Add Comment
Please, Sign In to add comment