langscan 1.2-x86-mswin32-60

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