libxml-ruby 0.7.0-x86-mswin32-60 → 0.8.0-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 (188) hide show
  1. data/CHANGES +24 -1
  2. data/README +48 -3
  3. data/benchmark/depixelate.rb +632 -0
  4. data/benchmark/hamlet.xml +9055 -0
  5. data/benchmark/sock_entries.xml +507 -0
  6. data/benchmark/throughput.rb +39 -0
  7. data/benchmark/xml_benchmarks.rb +222 -0
  8. data/doc/classes/LibXML.html +237 -0
  9. data/doc/classes/LibXML/XML.html +178 -0
  10. data/doc/classes/{XML → LibXML/XML}/Attr.html +213 -182
  11. data/doc/classes/{XML → LibXML/XML}/Attributes.html +126 -54
  12. data/doc/classes/{XML → LibXML/XML}/Document.html +299 -297
  13. data/doc/classes/{XML → LibXML/XML}/Dtd.html +10 -10
  14. data/doc/classes/{XML/XInclude → LibXML/XML}/Error.html +4 -4
  15. data/doc/classes/{XML → LibXML/XML}/HTMLParser.html +40 -40
  16. data/doc/classes/{XML → LibXML/XML}/InputCallbacks.html +10 -10
  17. data/doc/classes/{XML → LibXML/XML}/NS.html +46 -46
  18. data/doc/classes/{XML → LibXML/XML}/Node.html +935 -788
  19. data/doc/classes/LibXML/XML/Node/FailedModify.html +111 -0
  20. data/doc/classes/{XML → LibXML/XML}/Node/Set.html +69 -68
  21. data/doc/classes/{XML → LibXML/XML}/Node/SetNamespace.html +4 -4
  22. data/doc/classes/{XML/Node/FailedModify.html → LibXML/XML/Node/UnknownType.html} +4 -4
  23. data/doc/classes/{XML → LibXML/XML}/Parser.html +426 -389
  24. data/doc/classes/{XML → LibXML/XML}/Parser/Context.html +208 -208
  25. data/doc/classes/{XML → LibXML/XML}/Parser/ParseError.html +4 -4
  26. data/doc/classes/{XML → LibXML/XML}/Reader.html +288 -287
  27. data/doc/classes/{XML → LibXML/XML}/SaxParser.html +52 -52
  28. data/doc/classes/{XML/XPath/Context.html → LibXML/XML/Schema.html} +60 -32
  29. data/doc/classes/{XML → LibXML/XML}/State.html +4 -4
  30. data/doc/classes/{XML/Node/UnknownType.html → LibXML/XML/Tree.html} +5 -5
  31. data/doc/classes/{XML → LibXML/XML}/XInclude.html +5 -5
  32. data/doc/classes/{XML → LibXML/XML/XInclude}/Error.html +5 -5
  33. data/doc/classes/{XML → LibXML/XML}/XMLParserOptions.html +5 -5
  34. data/doc/classes/{XML → LibXML/XML}/XPath.html +23 -64
  35. data/doc/classes/LibXML/XML/XPath/Context.html +403 -0
  36. data/doc/classes/{XML/XPointer/Context → LibXML/XML/XPath}/InvalidPath.html +4 -4
  37. data/doc/classes/LibXML/XML/XPath/Object.html +623 -0
  38. data/doc/classes/{XML → LibXML/XML}/XPointer.html +12 -12
  39. data/doc/classes/{XML → LibXML/XML}/XPointer/Context.html +5 -5
  40. data/doc/classes/{XML/XPath → LibXML/XML/XPointer/Context}/InvalidPath.html +5 -5
  41. data/doc/classes/{XML → LibXML/XML}/XPointer/InvalidExpression.html +4 -4
  42. data/doc/classes/XML.html +17 -123
  43. data/doc/created.rid +1 -1
  44. data/doc/files/CHANGES.html +49 -25
  45. data/doc/files/LICENSE.html +1 -1
  46. data/doc/files/README.html +79 -4
  47. data/doc/files/VERSION.html +2 -2
  48. data/doc/files/ext/libxml/cbg_c.html +1 -1
  49. data/doc/files/ext/libxml/libxml_c.html +1 -1
  50. data/doc/files/ext/libxml/ruby_xml_attr_c.html +1 -1
  51. data/doc/files/ext/libxml/ruby_xml_attributes_c.html +1 -1
  52. data/doc/files/ext/libxml/ruby_xml_document_c.html +1 -1
  53. data/doc/files/ext/libxml/ruby_xml_dtd_c.html +1 -1
  54. data/doc/files/ext/libxml/ruby_xml_html_parser_c.html +1 -1
  55. data/doc/files/ext/libxml/ruby_xml_input_cbg_c.html +1 -1
  56. data/doc/files/ext/libxml/ruby_xml_node_c.html +1 -1
  57. data/doc/files/ext/libxml/ruby_xml_node_set_c.html +1 -1
  58. data/doc/files/ext/libxml/ruby_xml_ns_c.html +1 -1
  59. data/doc/files/ext/libxml/ruby_xml_parser_c.html +1 -1
  60. data/doc/files/ext/libxml/ruby_xml_parser_context_c.html +1 -1
  61. data/doc/files/ext/libxml/ruby_xml_reader_c.html +1 -1
  62. data/doc/files/ext/libxml/ruby_xml_sax_parser_c.html +1 -1
  63. data/doc/files/ext/libxml/ruby_xml_schema_c.html +1 -1
  64. data/doc/files/ext/libxml/ruby_xml_state_c.html +1 -1
  65. data/doc/files/ext/libxml/ruby_xml_xinclude_c.html +1 -1
  66. data/doc/files/ext/libxml/ruby_xml_xpath_c.html +1 -1
  67. data/doc/files/ext/libxml/ruby_xml_xpath_context_c.html +1 -1
  68. data/doc/files/ext/libxml/ruby_xml_xpath_object_c.html +1 -1
  69. data/doc/files/ext/libxml/ruby_xml_xpointer_c.html +1 -1
  70. data/doc/files/ext/libxml/ruby_xml_xpointer_context_c.html +1 -1
  71. data/doc/files/lib/libxml/attr_rb.html +108 -0
  72. data/doc/files/lib/libxml/attributes_rb.html +108 -0
  73. data/doc/files/lib/libxml/document_rb.html +108 -0
  74. data/doc/files/lib/libxml/node_rb.html +108 -0
  75. data/doc/files/lib/libxml/node_set_rb.html +108 -0
  76. data/doc/files/lib/libxml/parser_options_rb.html +107 -0
  77. data/doc/files/{ext/libxml/ruby_xml_tree_c.html → lib/libxml/parser_rb.html} +4 -4
  78. data/doc/files/lib/libxml/properties_rb.html +108 -0
  79. data/doc/files/lib/libxml/tree_rb.html +107 -0
  80. data/doc/files/lib/libxml_rb.html +12 -3
  81. data/doc/fr_class_index.html +34 -32
  82. data/doc/fr_file_index.html +9 -1
  83. data/doc/fr_method_index.html +362 -347
  84. data/ext/libxml/cbg.c +76 -76
  85. data/ext/libxml/libxml.c +4 -3
  86. data/ext/libxml/ruby_libxml.h +1 -1
  87. data/ext/libxml/ruby_xml_attr.c +4 -3
  88. data/ext/libxml/ruby_xml_attr.h +16 -16
  89. data/ext/libxml/ruby_xml_attributes.c +267 -266
  90. data/ext/libxml/ruby_xml_attributes.h +17 -17
  91. data/ext/libxml/ruby_xml_document.c +30 -59
  92. data/ext/libxml/ruby_xml_document.h +27 -27
  93. data/ext/libxml/ruby_xml_dtd.c +2 -1
  94. data/ext/libxml/ruby_xml_dtd.h +17 -17
  95. data/ext/libxml/ruby_xml_html_parser.c +3 -2
  96. data/ext/libxml/ruby_xml_html_parser.h +29 -29
  97. data/ext/libxml/ruby_xml_input_cbg.c +2 -1
  98. data/ext/libxml/ruby_xml_input_cbg.h +20 -20
  99. data/ext/libxml/ruby_xml_node.c +127 -470
  100. data/ext/libxml/ruby_xml_node.h +17 -17
  101. data/ext/libxml/ruby_xml_node_set.c +5 -4
  102. data/ext/libxml/ruby_xml_node_set.h +20 -20
  103. data/ext/libxml/ruby_xml_ns.c +3 -2
  104. data/ext/libxml/ruby_xml_ns.h +12 -12
  105. data/ext/libxml/ruby_xml_parser.c +20 -48
  106. data/ext/libxml/ruby_xml_parser.h +31 -31
  107. data/ext/libxml/ruby_xml_parser_context.c +3 -2
  108. data/ext/libxml/ruby_xml_parser_context.h +20 -20
  109. data/ext/libxml/ruby_xml_reader.c +2 -1
  110. data/ext/libxml/ruby_xml_sax_parser.c +3 -2
  111. data/ext/libxml/ruby_xml_sax_parser.h +56 -56
  112. data/ext/libxml/ruby_xml_schema.c +6 -0
  113. data/ext/libxml/ruby_xml_schema.h +16 -16
  114. data/ext/libxml/ruby_xml_state.c +13 -12
  115. data/ext/libxml/ruby_xml_state.h +1 -1
  116. data/ext/libxml/ruby_xml_xinclude.c +3 -2
  117. data/ext/libxml/ruby_xml_xinclude.h +13 -13
  118. data/ext/libxml/ruby_xml_xpath.c +35 -228
  119. data/ext/libxml/ruby_xml_xpath.h +22 -23
  120. data/ext/libxml/ruby_xml_xpath_context.c +223 -62
  121. data/ext/libxml/ruby_xml_xpath_context.h +15 -20
  122. data/ext/libxml/ruby_xml_xpath_object.c +63 -19
  123. data/ext/libxml/ruby_xml_xpointer.c +19 -15
  124. data/ext/libxml/ruby_xml_xpointer.h +27 -27
  125. data/ext/libxml/ruby_xml_xpointer_context.c +3 -2
  126. data/ext/libxml/ruby_xml_xpointer_context.h +18 -18
  127. data/ext/libxml/version.h +9 -9
  128. data/lib/libxml.rb +16 -128
  129. data/lib/libxml/attr.rb +45 -0
  130. data/lib/libxml/attributes.rb +15 -0
  131. data/lib/libxml/document.rb +54 -0
  132. data/lib/libxml/node.rb +132 -0
  133. data/lib/libxml/node_set.rb +27 -0
  134. data/lib/libxml/parser.rb +42 -0
  135. data/lib/libxml/parser_options.rb +25 -0
  136. data/lib/libxml/properties.rb +19 -0
  137. data/lib/libxml/tree.rb +29 -0
  138. data/lib/libxml_ruby.so +0 -0
  139. data/mingw/libxml_ruby.so +0 -0
  140. data/{work/task/setup → setup.rb} +1585 -1616
  141. data/test/gc.log +0 -0
  142. data/test/model/books.xml +147 -0
  143. data/{work/test/runner.rb → test/model/default_validation_bug.rb} +0 -0
  144. data/test/model/merge_bug_data.xml +58 -0
  145. data/test/model/rubynet.xml +78 -0
  146. data/test/model/rubynet_project +1 -0
  147. data/test/model/saxtest.xml +5 -0
  148. data/test/model/shiporder.xml +23 -0
  149. data/test/model/shiporder.xsd +31 -0
  150. data/test/model/simple.xml +7 -0
  151. data/test/model/soap.xml +27 -0
  152. data/test/model/xinclude.xml +5 -0
  153. data/test/tc_deprecated_require.rb +13 -0
  154. data/test/tc_xml_document.rb +57 -16
  155. data/test/tc_xml_document_write.rb +125 -10
  156. data/test/tc_xml_dtd.rb +22 -1
  157. data/test/tc_xml_node.rb +13 -0
  158. data/test/tc_xml_node_edit.rb +1 -1
  159. data/test/tc_xml_node_xlink.rb +1 -1
  160. data/test/tc_xml_parser.rb +64 -7
  161. data/test/tc_xml_properties.rb +42 -0
  162. data/test/tc_xml_reader.rb +4 -4
  163. data/test/tc_xml_sax_parser.rb +50 -50
  164. data/test/tc_xml_schema.rb +2 -2
  165. data/test/tc_xml_traversal.rb +220 -0
  166. data/test/tc_xml_xinclude.rb +12 -15
  167. data/test/tc_xml_xpath.rb +74 -6
  168. data/test/tc_xml_xpath_context.rb +72 -0
  169. data/test/test_suite.rb +6 -4
  170. data/vc/libxml_ruby.vcproj +1 -9
  171. metadata +92 -65
  172. data/doc/classes/XML/SiblingEnum.html +0 -142
  173. data/doc/classes/XML/Tree.html +0 -224
  174. data/doc/classes/XML/XPath/Object.html +0 -439
  175. data/ext/libxml/ruby_xml_tree.c +0 -43
  176. data/ext/libxml/ruby_xml_tree.h +0 -12
  177. data/test/ets_copy_bug2.rb +0 -21
  178. data/test/tc_xml_document_write2.rb +0 -54
  179. data/test/tc_xml_document_write3.rb +0 -96
  180. data/test/tc_xml_sax_parser2.rb +0 -51
  181. data/work/Rakefile +0 -247
  182. data/work/task/make +0 -26
  183. data/work/task/memory +0 -37
  184. data/work/task/rdoc +0 -39
  185. data/work/task/test +0 -29
  186. data/work/test/ets_runner.rb +0 -33
  187. data/work/test/libxml_test.rb +0 -3
  188. data/work/test/runner_ets.rb +0 -33
@@ -0,0 +1,132 @@
1
+ # $Id: libxml.rb 374 2008-07-11 04:51:41Z cfis $
2
+ # Please see the LICENSE file for copyright and distribution information
3
+
4
+ module LibXML
5
+ module XML
6
+ class Node
7
+ # Return nodes matching the specified xpath expression.
8
+ # For more information, please refer to the documentation
9
+ # for XML::Document#find.
10
+ def find(xpath, nslist = nil)
11
+ if not self.doc
12
+ raise(TypeError, "A node must belong to a document before " +
13
+ "it can be searched with XPath.")
14
+ end
15
+
16
+ context = XPath::Context.new(self)
17
+ context.node = self
18
+ context.register_namespaces_from_node(self)
19
+ context.register_namespaces_from_node(self.doc.root)
20
+ context.register_namespaces(nslist) if nslist
21
+
22
+ context.find(xpath)
23
+ end
24
+
25
+ # Return the first node matching the specified xpath expression.
26
+ # For more information, please refer to the documentation
27
+ # for XML::Node#find.
28
+ def find_first(xpath, nslist = nil)
29
+ find(xpath, nslist).first
30
+ end
31
+
32
+ def each_element
33
+ each do |node|
34
+ yield(node) if node.node_type == ELEMENT_NODE
35
+ end
36
+ end
37
+
38
+ # Determines whether this node has a parent node
39
+ def parent?
40
+ not parent.nil?
41
+ end
42
+
43
+ # Determines whether this node has a first node
44
+ def first?
45
+ not first.nil?
46
+ end
47
+
48
+ # Returns this node's children as an array.
49
+ def children
50
+ entries
51
+ end
52
+
53
+ # Determines whether this node has a next node
54
+ def next?
55
+ not self.next.nil?
56
+ end
57
+
58
+ # Determines whether this node has a previous node
59
+ def prev?
60
+ not prev.nil?
61
+ end
62
+
63
+ # Determines whether this node has a last node
64
+ def last?
65
+ not last.nil?
66
+ end
67
+
68
+ # Returns this node's type name
69
+ def node_type_name
70
+ case node_type
71
+ when ELEMENT_NODE:
72
+ 'element'
73
+ when ATTRIBUTE_NODE:
74
+ 'attribute'
75
+ when TEXT_NODE:
76
+ 'text'
77
+ when CDATA_SECTION_NODE:
78
+ 'cdata'
79
+ when ENTITY_REF_NODE:
80
+ 'entity_ref'
81
+ when ENTITY_NODE:
82
+ 'entity'
83
+ when PI_NODE:
84
+ 'pi'
85
+ when COMMENT_NODE:
86
+ 'comment'
87
+ when DOCUMENT_NODE:
88
+ 'document_xml'
89
+ when DOCUMENT_TYPE_NODE:
90
+ 'doctype'
91
+ when DOCUMENT_FRAG_NODE:
92
+ 'fragment'
93
+ when NOTATION_NODE:
94
+ 'notation'
95
+ when HTML_DOCUMENT_NODE:
96
+ 'document_html'
97
+ when DTD_NODE:
98
+ 'dtd'
99
+ when ELEMENT_DECL:
100
+ 'elem_decl'
101
+ when ATTRIBUTE_DECL:
102
+ 'attribute_decl'
103
+ when ENTITY_DECL:
104
+ 'entity_decl'
105
+ when NAMESPACE_DECL:
106
+ 'namespace'
107
+ when XINCLUDE_START:
108
+ 'xinclude_start'
109
+ when XINCLUDE_END:
110
+ 'xinclude_end'
111
+ when DOCB_DOCUMENT_NODE:
112
+ 'document_docbook'
113
+ else
114
+ raise(UnknownType, "Unknown node type: %n", node.node_type);
115
+ end
116
+ end
117
+
118
+ def dup
119
+ copy(false)
120
+ end
121
+
122
+ def clone
123
+ copy(false)
124
+ end
125
+
126
+ alias :child? :first?
127
+ alias :children? :first?
128
+ alias :child :first
129
+ alias :each_child :each
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,27 @@
1
+ # $Id: libxml.rb 374 2008-07-11 04:51:41Z cfis $
2
+ # Please see the LICENSE file for copyright and distribution information
3
+
4
+
5
+ module LibXML
6
+ module XML
7
+ class Node
8
+ class Set
9
+ include Enumerable
10
+
11
+ # inefficient, but maybe can find a way to cache the
12
+ # ary and dump on change?
13
+ def [](i, count = nil)
14
+ if count
15
+ to_a[i,count]
16
+ else
17
+ to_a[i]
18
+ end
19
+ end
20
+
21
+ def to_s #:nodoc:
22
+ to_a.to_s
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ module LibXML
2
+ module XML
3
+ class Parser
4
+ class << self
5
+ attr_reader :error_handler
6
+
7
+ # Register the attached block as the handler for parser errors.
8
+ #
9
+ # Parser.register_error_handler {|msg| <do stuff>}
10
+ # Parser.register_error_handler(lambda {|msg| <do stuff>})
11
+ # Parser.register_error_handler(nil)
12
+ #
13
+ # A message describing parse errors is passed to the block.
14
+ # Libxml passes error messages to the handler in parts, one per call.
15
+ # A typical error results in six calls to this proc, with arguments:
16
+ #
17
+ # "Entity: line 1: ",
18
+ # "parser ",
19
+ # "error : ",
20
+ # "Opening and ending tag mismatch: foo line 1 and foz\n",
21
+ # "<foo><bar/></foz>\n",
22
+ # " ^\n"
23
+ #
24
+ # Note that the error handler is shared by all threads.
25
+ def register_error_handler(value = nil, &block)
26
+ # Value may be nil or a proc.
27
+ tmp = self.error_handler
28
+ @error_handler = block_given? ? block : value
29
+ tmp
30
+ end
31
+
32
+ def xml_error_func_handler(msg)
33
+ if not self.error_handler
34
+ $stderr.puts(msg)
35
+ else
36
+ self.error_handler.call(msg)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ # $Id: libxml.rb 374 2008-07-11 04:51:41Z cfis $
2
+
3
+ module LibXML
4
+ module XML
5
+ module XMLParserOptions
6
+ XML_PARSE_RECOVER = 1 # recover on errors
7
+ XML_PARSE_NOENT = 2 # substitute entities
8
+ XML_PARSE_DTDLOAD = 4 # load the external subset
9
+ XML_PARSE_DTDATTR = 8 # default DTD attributes
10
+ XML_PARSE_DTDVALID = 16 # validate with the DTD
11
+ XML_PARSE_NOERROR = 32 # suppress error reports
12
+ XML_PARSE_NOWARNING = 64 # suppress warning reports
13
+ XML_PARSE_PEDANTIC = 128 # pedantic error reporting
14
+ XML_PARSE_NOBLANKS = 256 # remove blank nodes
15
+ XML_PARSE_SAX1 = 512 # use the SAX1 interface internally
16
+ XML_PARSE_XINCLUDE = 1024 # Implement XInclude substitition
17
+ XML_PARSE_NONET = 2048 # Forbid network access
18
+ XML_PARSE_NODICT = 4096 # Do not reuse the context dictionnary
19
+ XML_PARSE_NSCLEAN = 8192 # remove redundant namespaces declarations
20
+ XML_PARSE_NOCDATA = 16384 # merge CDATA as text nodes
21
+ XML_PARSE_NOXINCNODE = 32768 # do not generate XINCLUDE START/END nodes
22
+ XML_PARSE_COMPACT = 65536 # compact small text nodes; no modification of the tree allowed afterwards (will possibly crash if you try to modify the tree)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ # $Id: libxml.rb 374 2008-07-11 04:51:41Z cfis $
2
+ # Please see the LICENSE file for copyright and distribution information
3
+
4
+
5
+ # This is for backwards compatibility and is DEPRECATED
6
+ module LibXML
7
+ module XML
8
+ class Node
9
+ def properties
10
+ attributes
11
+ end
12
+ end
13
+
14
+ class Attributes
15
+ alias :each_attr :each
16
+ alias :each_sibling :each
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ # This is for backwards compatibility and is DEPRECATED
2
+ module LibXML
3
+ module XML
4
+ class Tree
5
+ # :enddoc:
6
+ ELEMENT_NODE = Node::ELEMENT_NODE
7
+ ATTRIBUTE_NODE = Node::ATTRIBUTE_NODE
8
+ TEXT_NODE = Node::TEXT_NODE
9
+ CDATA_SECTION_NODE = Node::CDATA_SECTION_NODE
10
+ ENTITY_REF_NODE = Node::ENTITY_REF_NODE
11
+ ENTITY_NODE = Node::ENTITY_NODE
12
+ PI_NODE = Node::PI_NODE
13
+ COMMENT_NODE = Node::COMMENT_NODE
14
+ DOCUMENT_NODE = Node::DOCUMENT_NODE
15
+ DOCUMENT_TYPE_NODE = Node::DOCUMENT_TYPE_NODE
16
+ DOCUMENT_FRAG_NODE = Node::DOCUMENT_FRAG_NODE
17
+ NOTATION_NODE = Node::NOTATION_NODE
18
+ HTML_DOCUMENT_NODE = Node::HTML_DOCUMENT_NODE
19
+ DTD_NODE = Node::DTD_NODE
20
+ ELEMENT_DECL = Node::ELEMENT_DECL
21
+ ATTRIBUTE_DECL = Node::ATTRIBUTE_DECL
22
+ ENTITY_DECL = Node::ENTITY_DECL
23
+ NAMESPACE_DECL = Node::NAMESPACE_DECL
24
+ XINCLUDE_START = Node::XINCLUDE_START
25
+ XINCLUDE_END = Node::XINCLUDE_END
26
+ DOCB_DOCUMENT_NODE = Node::DOCB_DOCUMENT_NODE
27
+ end
28
+ end
29
+ end
Binary file
Binary file
@@ -1,1616 +1,1585 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Setup and install.
4
- #
5
- # setup.rb
6
- #
7
- # Copyright (c) 2000-2005 Minero Aoki
8
- #
9
- # This program is free software.
10
- # You can distribute/modify this program under the terms of
11
- # the GNU LGPL, Lesser General Public License version 2.1.
12
-
13
- #
14
- # Was hardcoded as 'InstalledFiles'
15
- #
16
-
17
- INSTALLED_MANIFEST = '.installed'
18
-
19
- #
20
- # Was hardcoded as 'packages'.
21
- #
22
-
23
- PACKAGES_DIRECTORY = 'src'
24
-
25
- #
26
- # Locate and move to the root dir of the project/package.
27
- # This is setup to put setup in a utilities subdir.
28
- #
29
- # TODO Make more robust.
30
- #
31
-
32
- ROOT_DIRECTORY = File.dirname(File.dirname(File.expand_path($0)))
33
-
34
- Dir.chdir(ROOT_DIRECTORY)
35
-
36
- #
37
- # Deal with Ruby version issues.
38
- #
39
-
40
- unless Enumerable.method_defined?(:map) # Ruby 1.4.6
41
- module Enumerable
42
- alias map collect
43
- end
44
- end
45
-
46
- unless File.respond_to?(:read) # Ruby 1.6
47
- def File.read(fname)
48
- open(fname) {|f|
49
- return f.read
50
- }
51
- end
52
- end
53
-
54
- unless Errno.const_defined?(:ENOTEMPTY) # Windows?
55
- module Errno
56
- class ENOTEMPTY
57
- # We do not raise this exception, implementation is not needed.
58
- end
59
- end
60
- end
61
-
62
- def File.binread(fname)
63
- open(fname, 'rb') {|f|
64
- return f.read
65
- }
66
- end
67
-
68
- # for corrupted Windows' stat(2)
69
- def File.dir?(path)
70
- File.directory?((path[-1,1] == '/') ? path : path + '/')
71
- end
72
-
73
-
74
- class ConfigTable
75
-
76
- include Enumerable
77
-
78
- def initialize(rbconfig)
79
- @rbconfig = rbconfig
80
- @items = []
81
- @table = {}
82
- # options
83
- @install_prefix = nil
84
- @config_opt = nil
85
- @verbose = true
86
- @no_harm = false
87
- end
88
-
89
- attr_accessor :install_prefix
90
- attr_accessor :config_opt
91
-
92
- attr_writer :verbose
93
-
94
- def verbose?
95
- @verbose
96
- end
97
-
98
- attr_writer :no_harm
99
-
100
- def no_harm?
101
- @no_harm
102
- end
103
-
104
- def [](key)
105
- lookup(key).resolve(self)
106
- end
107
-
108
- def []=(key, val)
109
- lookup(key).set val
110
- end
111
-
112
- def names
113
- @items.map {|i| i.name }
114
- end
115
-
116
- def each(&block)
117
- @items.each(&block)
118
- end
119
-
120
- def key?(name)
121
- @table.key?(name)
122
- end
123
-
124
- def lookup(name)
125
- @table[name] or setup_rb_error "no such config item: #{name}"
126
- end
127
-
128
- def add(item)
129
- @items.push item
130
- @table[item.name] = item
131
- end
132
-
133
- def remove(name)
134
- item = lookup(name)
135
- @items.delete_if {|i| i.name == name }
136
- @table.delete_if {|name, i| i.name == name }
137
- item
138
- end
139
-
140
- def load_script(path, inst = nil)
141
- if File.file?(path)
142
- MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
143
- end
144
- end
145
-
146
- def savefile
147
- '.config'
148
- end
149
-
150
- def load_savefile
151
- begin
152
- File.foreach(savefile()) do |line|
153
- k, v = *line.split(/=/, 2)
154
- self[k] = v.strip
155
- end
156
- rescue Errno::ENOENT
157
- setup_rb_error $!.message + "\n#{File.basename($0)} config first"
158
- end
159
- end
160
-
161
- def save
162
- @items.each {|i| i.value }
163
- File.open(savefile(), 'w') {|f|
164
- @items.each do |i|
165
- f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
166
- end
167
- }
168
- end
169
-
170
- def load_standard_entries
171
- standard_entries(@rbconfig).each do |ent|
172
- add ent
173
- end
174
- end
175
-
176
- def standard_entries(rbconfig)
177
- c = rbconfig
178
-
179
- rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
180
-
181
- major = c['MAJOR'].to_i
182
- minor = c['MINOR'].to_i
183
- teeny = c['TEENY'].to_i
184
- version = "#{major}.#{minor}"
185
-
186
- # ruby ver. >= 1.4.4?
187
- newpath_p = ((major >= 2) or
188
- ((major == 1) and
189
- ((minor >= 5) or
190
- ((minor == 4) and (teeny >= 4)))))
191
-
192
- if c['rubylibdir']
193
- # V > 1.6.3
194
- libruby = "#{c['prefix']}/lib/ruby"
195
- librubyver = c['rubylibdir']
196
- librubyverarch = c['archdir']
197
- siteruby = c['sitedir']
198
- siterubyver = c['sitelibdir']
199
- siterubyverarch = c['sitearchdir']
200
- elsif newpath_p
201
- # 1.4.4 <= V <= 1.6.3
202
- libruby = "#{c['prefix']}/lib/ruby"
203
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
204
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
205
- siteruby = c['sitedir']
206
- siterubyver = "$siteruby/#{version}"
207
- siterubyverarch = "$siterubyver/#{c['arch']}"
208
- else
209
- # V < 1.4.4
210
- libruby = "#{c['prefix']}/lib/ruby"
211
- librubyver = "#{c['prefix']}/lib/ruby/#{version}"
212
- librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
213
- siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
214
- siterubyver = siteruby
215
- siterubyverarch = "$siterubyver/#{c['arch']}"
216
- end
217
- parameterize = lambda {|path|
218
- path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
219
- }
220
-
221
- if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
222
- makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
223
- else
224
- makeprog = 'make'
225
- end
226
-
227
- [
228
- ExecItem.new('installdirs', 'std/site/home',
229
- 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
230
- {|val, table|
231
- case val
232
- when 'std'
233
- table['rbdir'] = '$librubyver'
234
- table['sodir'] = '$librubyverarch'
235
- when 'site'
236
- table['rbdir'] = '$siterubyver'
237
- table['sodir'] = '$siterubyverarch'
238
- when 'home'
239
- setup_rb_error '$HOME was not set' unless ENV['HOME']
240
- table['prefix'] = ENV['HOME']
241
- table['rbdir'] = '$libdir/ruby'
242
- table['sodir'] = '$libdir/ruby'
243
- end
244
- },
245
- PathItem.new('prefix', 'path', c['prefix'],
246
- 'path prefix of target environment'),
247
- PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
248
- 'the directory for commands'),
249
- PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
250
- 'the directory for libraries'),
251
- PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
252
- 'the directory for shared data'),
253
- PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
254
- 'the directory for man pages'),
255
- PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
256
- 'the directory for system configuration files'),
257
- PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
258
- 'the directory for local state data'),
259
- PathItem.new('libruby', 'path', libruby,
260
- 'the directory for ruby libraries'),
261
- PathItem.new('librubyver', 'path', librubyver,
262
- 'the directory for standard ruby libraries'),
263
- PathItem.new('librubyverarch', 'path', librubyverarch,
264
- 'the directory for standard ruby extensions'),
265
- PathItem.new('siteruby', 'path', siteruby,
266
- 'the directory for version-independent aux ruby libraries'),
267
- PathItem.new('siterubyver', 'path', siterubyver,
268
- 'the directory for aux ruby libraries'),
269
- PathItem.new('siterubyverarch', 'path', siterubyverarch,
270
- 'the directory for aux ruby binaries'),
271
- PathItem.new('rbdir', 'path', '$siterubyver',
272
- 'the directory for ruby scripts'),
273
- PathItem.new('sodir', 'path', '$siterubyverarch',
274
- 'the directory for ruby extentions'),
275
- PathItem.new('rubypath', 'path', rubypath,
276
- 'the path to set to #! line'),
277
- ProgramItem.new('rubyprog', 'name', rubypath,
278
- 'the ruby program using for installation'),
279
- ProgramItem.new('makeprog', 'name', makeprog,
280
- 'the make program to compile ruby extentions'),
281
- SelectItem.new('shebang', 'all/ruby/never', 'ruby',
282
- 'shebang line (#!) editing mode'),
283
- BoolItem.new('without-ext', 'yes/no', 'no',
284
- 'does not compile/install ruby extentions')
285
- ]
286
- end
287
- private :standard_entries
288
-
289
- def load_multipackage_entries
290
- multipackage_entries().each do |ent|
291
- add ent
292
- end
293
- end
294
-
295
- def multipackage_entries
296
- [
297
- PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
298
- 'package names that you want to install'),
299
- PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
300
- 'package names that you do not want to install')
301
- ]
302
- end
303
- private :multipackage_entries
304
-
305
- ALIASES = {
306
- 'std-ruby' => 'librubyver',
307
- 'stdruby' => 'librubyver',
308
- 'rubylibdir' => 'librubyver',
309
- 'archdir' => 'librubyverarch',
310
- 'site-ruby-common' => 'siteruby', # For backward compatibility
311
- 'site-ruby' => 'siterubyver', # For backward compatibility
312
- 'bin-dir' => 'bindir',
313
- 'bin-dir' => 'bindir',
314
- 'rb-dir' => 'rbdir',
315
- 'so-dir' => 'sodir',
316
- 'data-dir' => 'datadir',
317
- 'ruby-path' => 'rubypath',
318
- 'ruby-prog' => 'rubyprog',
319
- 'ruby' => 'rubyprog',
320
- 'make-prog' => 'makeprog',
321
- 'make' => 'makeprog'
322
- }
323
-
324
- def fixup
325
- ALIASES.each do |ali, name|
326
- @table[ali] = @table[name]
327
- end
328
- @items.freeze
329
- @table.freeze
330
- @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
331
- end
332
-
333
- def parse_opt(opt)
334
- m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
335
- m.to_a[1,2]
336
- end
337
-
338
- def dllext
339
- @rbconfig['DLEXT']
340
- end
341
-
342
- def value_config?(name)
343
- lookup(name).value?
344
- end
345
-
346
- class Item
347
- def initialize(name, template, default, desc)
348
- @name = name.freeze
349
- @template = template
350
- @value = default
351
- @default = default
352
- @description = desc
353
- end
354
-
355
- attr_reader :name
356
- attr_reader :description
357
-
358
- attr_accessor :default
359
- alias help_default default
360
-
361
- def help_opt
362
- "--#{@name}=#{@template}"
363
- end
364
-
365
- def value?
366
- true
367
- end
368
-
369
- def value
370
- @value
371
- end
372
-
373
- def resolve(table)
374
- @value.gsub(%r<\$([^/]+)>) { table[$1] }
375
- end
376
-
377
- def set(val)
378
- @value = check(val)
379
- end
380
-
381
- private
382
-
383
- def check(val)
384
- setup_rb_error "config: --#{name} requires argument" unless val
385
- val
386
- end
387
- end
388
-
389
- class BoolItem < Item
390
- def config_type
391
- 'bool'
392
- end
393
-
394
- def help_opt
395
- "--#{@name}"
396
- end
397
-
398
- private
399
-
400
- def check(val)
401
- return 'yes' unless val
402
- case val
403
- when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
404
- when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
405
- else
406
- setup_rb_error "config: --#{@name} accepts only yes/no for argument"
407
- end
408
- end
409
- end
410
-
411
- class PathItem < Item
412
- def config_type
413
- 'path'
414
- end
415
-
416
- private
417
-
418
- def check(path)
419
- setup_rb_error "config: --#{@name} requires argument" unless path
420
- path[0,1] == '$' ? path : File.expand_path(path)
421
- end
422
- end
423
-
424
- class ProgramItem < Item
425
- def config_type
426
- 'program'
427
- end
428
- end
429
-
430
- class SelectItem < Item
431
- def initialize(name, selection, default, desc)
432
- super
433
- @ok = selection.split('/')
434
- end
435
-
436
- def config_type
437
- 'select'
438
- end
439
-
440
- private
441
-
442
- def check(val)
443
- unless @ok.include?(val.strip)
444
- setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
445
- end
446
- val.strip
447
- end
448
- end
449
-
450
- class ExecItem < Item
451
- def initialize(name, selection, desc, &block)
452
- super name, selection, nil, desc
453
- @ok = selection.split('/')
454
- @action = block
455
- end
456
-
457
- def config_type
458
- 'exec'
459
- end
460
-
461
- def value?
462
- false
463
- end
464
-
465
- def resolve(table)
466
- setup_rb_error "$#{name()} wrongly used as option value"
467
- end
468
-
469
- undef set
470
-
471
- def evaluate(val, table)
472
- v = val.strip.downcase
473
- unless @ok.include?(v)
474
- setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
475
- end
476
- @action.call v, table
477
- end
478
- end
479
-
480
- class PackageSelectionItem < Item
481
- def initialize(name, template, default, help_default, desc)
482
- super name, template, default, desc
483
- @help_default = help_default
484
- end
485
-
486
- attr_reader :help_default
487
-
488
- def config_type
489
- 'package'
490
- end
491
-
492
- private
493
-
494
- def check(val)
495
- unless File.dir?("#{PACKAGES_DIRECTORY}/#{val}")
496
- setup_rb_error "config: no such package: #{val}"
497
- end
498
- val
499
- end
500
- end
501
-
502
- class MetaConfigEnvironment
503
- def initialize(config, installer)
504
- @config = config
505
- @installer = installer
506
- end
507
-
508
- def config_names
509
- @config.names
510
- end
511
-
512
- def config?(name)
513
- @config.key?(name)
514
- end
515
-
516
- def bool_config?(name)
517
- @config.lookup(name).config_type == 'bool'
518
- end
519
-
520
- def path_config?(name)
521
- @config.lookup(name).config_type == 'path'
522
- end
523
-
524
- def value_config?(name)
525
- @config.lookup(name).config_type != 'exec'
526
- end
527
-
528
- def add_config(item)
529
- @config.add item
530
- end
531
-
532
- def add_bool_config(name, default, desc)
533
- @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
534
- end
535
-
536
- def add_path_config(name, default, desc)
537
- @config.add PathItem.new(name, 'path', default, desc)
538
- end
539
-
540
- def set_config_default(name, default)
541
- @config.lookup(name).default = default
542
- end
543
-
544
- def remove_config(name)
545
- @config.remove(name)
546
- end
547
-
548
- # For only multipackage
549
- def packages
550
- raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
551
- @installer.packages
552
- end
553
-
554
- # For only multipackage
555
- def declare_packages(list)
556
- raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
557
- @installer.packages = list
558
- end
559
- end
560
-
561
- end # class ConfigTable
562
-
563
-
564
- # This module requires: #verbose?, #no_harm?
565
- module FileOperations
566
-
567
- def mkdir_p(dirname, prefix = nil)
568
- dirname = prefix + File.expand_path(dirname) if prefix
569
- $stderr.puts "mkdir -p #{dirname}" if verbose?
570
- return if no_harm?
571
-
572
- # Does not check '/', it's too abnormal.
573
- dirs = File.expand_path(dirname).split(%r<(?=/)>)
574
- if /\A[a-z]:\z/i =~ dirs[0]
575
- disk = dirs.shift
576
- dirs[0] = disk + dirs[0]
577
- end
578
- dirs.each_index do |idx|
579
- path = dirs[0..idx].join('')
580
- Dir.mkdir path unless File.dir?(path)
581
- end
582
- end
583
-
584
- def rm_f(path)
585
- $stderr.puts "rm -f #{path}" if verbose?
586
- return if no_harm?
587
- force_remove_file path
588
- end
589
-
590
- def rm_rf(path)
591
- $stderr.puts "rm -rf #{path}" if verbose?
592
- return if no_harm?
593
- remove_tree path
594
- end
595
-
596
- def remove_tree(path)
597
- if File.symlink?(path)
598
- remove_file path
599
- elsif File.dir?(path)
600
- remove_tree0 path
601
- else
602
- force_remove_file path
603
- end
604
- end
605
-
606
- def remove_tree0(path)
607
- Dir.foreach(path) do |ent|
608
- next if ent == '.'
609
- next if ent == '..'
610
- entpath = "#{path}/#{ent}"
611
- if File.symlink?(entpath)
612
- remove_file entpath
613
- elsif File.dir?(entpath)
614
- remove_tree0 entpath
615
- else
616
- force_remove_file entpath
617
- end
618
- end
619
- begin
620
- Dir.rmdir path
621
- rescue Errno::ENOTEMPTY
622
- # directory may not be empty
623
- end
624
- end
625
-
626
- def move_file(src, dest)
627
- force_remove_file dest
628
- begin
629
- File.rename src, dest
630
- rescue
631
- File.open(dest, 'wb') {|f|
632
- f.write File.binread(src)
633
- }
634
- File.chmod File.stat(src).mode, dest
635
- File.unlink src
636
- end
637
- end
638
-
639
- def force_remove_file(path)
640
- begin
641
- remove_file path
642
- rescue
643
- end
644
- end
645
-
646
- def remove_file(path)
647
- File.chmod 0777, path
648
- File.unlink path
649
- end
650
-
651
- def install(from, dest, mode, prefix = nil)
652
- $stderr.puts "install #{from} #{dest}" if verbose?
653
- return if no_harm?
654
-
655
- realdest = prefix ? prefix + File.expand_path(dest) : dest
656
- realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
657
- str = File.binread(from)
658
- if diff?(str, realdest)
659
- verbose_off {
660
- rm_f realdest if File.exist?(realdest)
661
- }
662
- File.open(realdest, 'wb') {|f|
663
- f.write str
664
- }
665
- File.chmod mode, realdest
666
-
667
- File.open("#{objdir_root()}/#{INSTALLED_MANIFEST}", 'a') {|f|
668
- if prefix
669
- f.puts realdest.sub(prefix, '')
670
- else
671
- f.puts realdest
672
- end
673
- }
674
- end
675
- end
676
-
677
- def diff?(new_content, path)
678
- return true unless File.exist?(path)
679
- new_content != File.binread(path)
680
- end
681
-
682
- def command(*args)
683
- $stderr.puts args.join(' ') if verbose?
684
- system(*args) or raise RuntimeError,
685
- "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
686
- end
687
-
688
- def ruby(*args)
689
- command config('rubyprog'), *args
690
- end
691
-
692
- def make(task = nil)
693
- command(*[config('makeprog'), task].compact)
694
- end
695
-
696
- def extdir?(dir)
697
- File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
698
- end
699
-
700
- def files_of(dir)
701
- Dir.open(dir) {|d|
702
- return d.select {|ent| File.file?("#{dir}/#{ent}") }
703
- }
704
- end
705
-
706
- DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
707
-
708
- def directories_of(dir)
709
- Dir.open(dir) {|d|
710
- return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
711
- }
712
- end
713
-
714
- end
715
-
716
-
717
- # This module requires: #srcdir_root, #objdir_root, #relpath
718
- module HookScriptAPI
719
-
720
- def get_config(key)
721
- @config[key]
722
- end
723
-
724
- alias config get_config
725
-
726
- # obsolete: use metaconfig to change configuration
727
- def set_config(key, val)
728
- @config[key] = val
729
- end
730
-
731
- #
732
- # srcdir/objdir (works only in the package directory)
733
- #
734
-
735
- def curr_srcdir
736
- "#{srcdir_root()}/#{relpath()}"
737
- end
738
-
739
- def curr_objdir
740
- "#{objdir_root()}/#{relpath()}"
741
- end
742
-
743
- def srcfile(path)
744
- "#{curr_srcdir()}/#{path}"
745
- end
746
-
747
- def srcexist?(path)
748
- File.exist?(srcfile(path))
749
- end
750
-
751
- def srcdirectory?(path)
752
- File.dir?(srcfile(path))
753
- end
754
-
755
- def srcfile?(path)
756
- File.file?(srcfile(path))
757
- end
758
-
759
- def srcentries(path = '.')
760
- Dir.open("#{curr_srcdir()}/#{path}") {|d|
761
- return d.to_a - %w(. ..)
762
- }
763
- end
764
-
765
- def srcfiles(path = '.')
766
- srcentries(path).select {|fname|
767
- File.file?(File.join(curr_srcdir(), path, fname))
768
- }
769
- end
770
-
771
- def srcdirectories(path = '.')
772
- srcentries(path).select {|fname|
773
- File.dir?(File.join(curr_srcdir(), path, fname))
774
- }
775
- end
776
-
777
- end
778
-
779
-
780
- class ToplevelInstaller
781
-
782
- Version = '3.4.1'
783
- Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
784
-
785
- TASKS = [
786
- [ 'all', 'do config, setup, then install' ],
787
- [ 'config', 'saves your configurations' ],
788
- [ 'show', 'shows current configuration' ],
789
- [ 'setup', 'compiles ruby extentions and others' ],
790
- [ 'install', 'installs files' ],
791
- [ 'test', 'run all tests in test/' ],
792
- [ 'clean', "does `make clean' for each extention" ],
793
- [ 'distclean',"does `make distclean' for each extention" ]
794
- ]
795
-
796
- def ToplevelInstaller.invoke
797
- config = ConfigTable.new(load_rbconfig())
798
- config.load_standard_entries
799
- config.load_multipackage_entries if multipackage?
800
- config.fixup
801
- klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
802
- #klass.new(File.dirname($0), config).invoke
803
- klass.new(ROOT_DIRECTORY, config).invoke
804
- end
805
-
806
- def ToplevelInstaller.multipackage?
807
- #File.dir?(File.dirname($0) + '/#{PACKAGES_DIRECTORY}')
808
- File.dir?(ROOT_DIRECTORY + "/#{PACKAGES_DIRECTORY}")
809
- end
810
-
811
- def ToplevelInstaller.load_rbconfig
812
- if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
813
- ARGV.delete(arg)
814
- load File.expand_path(arg.split(/=/, 2)[1])
815
- $".push 'rbconfig.rb'
816
- else
817
- require 'rbconfig'
818
- end
819
- ::Config::CONFIG
820
- end
821
-
822
- def initialize(ardir_root, config)
823
- @ardir = File.expand_path(ardir_root)
824
- @config = config
825
- # cache
826
- @valid_task_re = nil
827
- end
828
-
829
- def config(key)
830
- @config[key]
831
- end
832
-
833
- def inspect
834
- "#<#{self.class} #{__id__()}>"
835
- end
836
-
837
- def invoke
838
- run_metaconfigs
839
- case task = parsearg_global()
840
- when nil, 'all'
841
- parsearg_config
842
- init_installers
843
- exec_config
844
- exec_setup
845
- exec_install
846
- else
847
- case task
848
- when 'config', 'test'
849
- ;
850
- when 'clean', 'distclean'
851
- @config.load_savefile if File.exist?(@config.savefile)
852
- else
853
- @config.load_savefile
854
- end
855
- __send__ "parsearg_#{task}"
856
- init_installers
857
- __send__ "exec_#{task}"
858
- end
859
- end
860
-
861
- def run_metaconfigs
862
- @config.load_script "#{@ardir}/metaconfig"
863
- end
864
-
865
- def init_installers
866
- @installer = Installer.new(@config, @ardir, File.expand_path('.'))
867
- end
868
-
869
- #
870
- # Hook Script API bases
871
- #
872
-
873
- def srcdir_root
874
- @ardir
875
- end
876
-
877
- def objdir_root
878
- '.'
879
- end
880
-
881
- def relpath
882
- '.'
883
- end
884
-
885
- #
886
- # Option Parsing
887
- #
888
-
889
- def parsearg_global
890
- while arg = ARGV.shift
891
- case arg
892
- when /\A\w+\z/
893
- setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
894
- return arg
895
- when '-q', '--quiet'
896
- @config.verbose = false
897
- when '--verbose'
898
- @config.verbose = true
899
- when '--help'
900
- print_usage $stdout
901
- exit 0
902
- when '--version'
903
- puts "#{File.basename($0)} version #{Version}"
904
- exit 0
905
- when '--copyright'
906
- puts Copyright
907
- exit 0
908
- else
909
- setup_rb_error "unknown global option '#{arg}'"
910
- end
911
- end
912
- nil
913
- end
914
-
915
- def valid_task?(t)
916
- valid_task_re() =~ t
917
- end
918
-
919
- def valid_task_re
920
- @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
921
- end
922
-
923
- def parsearg_no_options
924
- unless ARGV.empty?
925
- task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
926
- setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
927
- end
928
- end
929
-
930
- alias parsearg_show parsearg_no_options
931
- alias parsearg_setup parsearg_no_options
932
- alias parsearg_test parsearg_no_options
933
- alias parsearg_clean parsearg_no_options
934
- alias parsearg_distclean parsearg_no_options
935
-
936
- def parsearg_config
937
- evalopt = []
938
- set = []
939
- @config.config_opt = []
940
- while i = ARGV.shift
941
- if /\A--?\z/ =~ i
942
- @config.config_opt = ARGV.dup
943
- break
944
- end
945
- name, value = *@config.parse_opt(i)
946
- if @config.value_config?(name)
947
- @config[name] = value
948
- else
949
- evalopt.push [name, value]
950
- end
951
- set.push name
952
- end
953
- evalopt.each do |name, value|
954
- @config.lookup(name).evaluate value, @config
955
- end
956
- # Check if configuration is valid
957
- set.each do |n|
958
- @config[n] if @config.value_config?(n)
959
- end
960
- end
961
-
962
- def parsearg_install
963
- @config.no_harm = false
964
- @config.install_prefix = ''
965
- while a = ARGV.shift
966
- case a
967
- when '--no-harm'
968
- @config.no_harm = true
969
- when /\A--prefix=/
970
- path = a.split(/=/, 2)[1]
971
- path = File.expand_path(path) unless path[0,1] == '/'
972
- @config.install_prefix = path
973
- else
974
- setup_rb_error "install: unknown option #{a}"
975
- end
976
- end
977
- end
978
-
979
- def print_usage(out)
980
- out.puts 'Typical Installation Procedure:'
981
- out.puts " $ ruby #{File.basename $0} config"
982
- out.puts " $ ruby #{File.basename $0} setup"
983
- out.puts " # ruby #{File.basename $0} install (may require root privilege)"
984
- out.puts
985
- out.puts 'Detailed Usage:'
986
- out.puts " ruby #{File.basename $0} <global option>"
987
- out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
988
-
989
- fmt = " %-24s %s\n"
990
- out.puts
991
- out.puts 'Global options:'
992
- out.printf fmt, '-q,--quiet', 'suppress message outputs'
993
- out.printf fmt, ' --verbose', 'output messages verbosely'
994
- out.printf fmt, ' --help', 'print this message'
995
- out.printf fmt, ' --version', 'print version and quit'
996
- out.printf fmt, ' --copyright', 'print copyright and quit'
997
- out.puts
998
- out.puts 'Tasks:'
999
- TASKS.each do |name, desc|
1000
- out.printf fmt, name, desc
1001
- end
1002
-
1003
- fmt = " %-24s %s [%s]\n"
1004
- out.puts
1005
- out.puts 'Options for CONFIG or ALL:'
1006
- @config.each do |item|
1007
- out.printf fmt, item.help_opt, item.description, item.help_default
1008
- end
1009
- out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
1010
- out.puts
1011
- out.puts 'Options for INSTALL:'
1012
- out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
1013
- out.printf fmt, '--prefix=path', 'install path prefix', ''
1014
- out.puts
1015
- end
1016
-
1017
- #
1018
- # Task Handlers
1019
- #
1020
-
1021
- def exec_config
1022
- @installer.exec_config
1023
- @config.save # must be final
1024
- end
1025
-
1026
- def exec_setup
1027
- @installer.exec_setup
1028
- end
1029
-
1030
- def exec_install
1031
- @installer.exec_install
1032
- end
1033
-
1034
- def exec_test
1035
- @installer.exec_test
1036
- end
1037
-
1038
- def exec_show
1039
- @config.each do |i|
1040
- printf "%-20s %s\n", i.name, i.value if i.value?
1041
- end
1042
- end
1043
-
1044
- def exec_clean
1045
- @installer.exec_clean
1046
- end
1047
-
1048
- def exec_distclean
1049
- @installer.exec_distclean
1050
- end
1051
-
1052
- end # class ToplevelInstaller
1053
-
1054
-
1055
- class ToplevelInstallerMulti < ToplevelInstaller
1056
-
1057
- include FileOperations
1058
-
1059
- def initialize(ardir_root, config)
1060
- super
1061
- @packages = directories_of("#{@ardir}/#{PACKAGES_DIRECTORY}")
1062
- raise 'no package exists' if @packages.empty?
1063
- @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1064
- end
1065
-
1066
- def run_metaconfigs
1067
- @config.load_script "#{@ardir}/metaconfig", self
1068
- @packages.each do |name|
1069
- @config.load_script "#{@ardir}/#{PACKAGES_DIRECTORY}/#{name}/metaconfig"
1070
- end
1071
- end
1072
-
1073
- attr_reader :packages
1074
-
1075
- def packages=(list)
1076
- raise 'package list is empty' if list.empty?
1077
- list.each do |name|
1078
- raise "directory #{PACKAGES_DIRECTORY}/#{name} does not exist"\
1079
- unless File.dir?("#{@ardir}/#{PACKAGES_DIRECTORY}/#{name}")
1080
- end
1081
- @packages = list
1082
- end
1083
-
1084
- def init_installers
1085
- @installers = {}
1086
- @packages.each do |pack|
1087
- @installers[pack] = Installer.new(@config,
1088
- "#{@ardir}/#{PACKAGES_DIRECTORY}/#{pack}",
1089
- "#{PACKAGES_DIRECTORY}/#{pack}")
1090
- end
1091
- with = extract_selection(config('with'))
1092
- without = extract_selection(config('without'))
1093
- @selected = @installers.keys.select {|name|
1094
- (with.empty? or with.include?(name)) \
1095
- and not without.include?(name)
1096
- }
1097
- end
1098
-
1099
- def extract_selection(list)
1100
- a = list.split(/,/)
1101
- a.each do |name|
1102
- setup_rb_error "no such package: #{name}" unless @installers.key?(name)
1103
- end
1104
- a
1105
- end
1106
-
1107
- def print_usage(f)
1108
- super
1109
- f.puts 'Inluded packages:'
1110
- f.puts ' ' + @packages.sort.join(' ')
1111
- f.puts
1112
- end
1113
-
1114
- #
1115
- # Task Handlers
1116
- #
1117
-
1118
- def exec_config
1119
- run_hook 'pre-config'
1120
- each_selected_installers {|inst| inst.exec_config }
1121
- run_hook 'post-config'
1122
- @config.save # must be final
1123
- end
1124
-
1125
- def exec_setup
1126
- run_hook 'pre-setup'
1127
- each_selected_installers {|inst| inst.exec_setup }
1128
- run_hook 'post-setup'
1129
- end
1130
-
1131
- def exec_install
1132
- run_hook 'pre-install'
1133
- each_selected_installers {|inst| inst.exec_install }
1134
- run_hook 'post-install'
1135
- end
1136
-
1137
- def exec_test
1138
- run_hook 'pre-test'
1139
- each_selected_installers {|inst| inst.exec_test }
1140
- run_hook 'post-test'
1141
- end
1142
-
1143
- def exec_clean
1144
- rm_f @config.savefile
1145
- run_hook 'pre-clean'
1146
- each_selected_installers {|inst| inst.exec_clean }
1147
- run_hook 'post-clean'
1148
- end
1149
-
1150
- def exec_distclean
1151
- rm_f @config.savefile
1152
- run_hook 'pre-distclean'
1153
- each_selected_installers {|inst| inst.exec_distclean }
1154
- run_hook 'post-distclean'
1155
- end
1156
-
1157
- #
1158
- # lib
1159
- #
1160
-
1161
- def each_selected_installers
1162
- Dir.mkdir PACKAGES_DIRECTORY unless File.dir?(PACKAGES_DIRECTORY)
1163
- @selected.each do |pack|
1164
- $stderr.puts "Processing the package `#{pack}' ..." if verbose?
1165
- Dir.mkdir "#{PACKAGES_DIRECTORY}/#{pack}" unless File.dir?("#{PACKAGES_DIRECTORY}/#{pack}")
1166
- Dir.chdir "#{PACKAGES_DIRECTORY}/#{pack}"
1167
- yield @installers[pack]
1168
- Dir.chdir '../..'
1169
- end
1170
- end
1171
-
1172
- def run_hook(id)
1173
- @root_installer.run_hook id
1174
- end
1175
-
1176
- # module FileOperations requires this
1177
- def verbose?
1178
- @config.verbose?
1179
- end
1180
-
1181
- # module FileOperations requires this
1182
- def no_harm?
1183
- @config.no_harm?
1184
- end
1185
-
1186
- end # class ToplevelInstallerMulti
1187
-
1188
-
1189
- class Installer
1190
-
1191
- FILETYPES = %w( bin lib ext data conf man )
1192
-
1193
- include FileOperations
1194
- include HookScriptAPI
1195
-
1196
- def initialize(config, srcroot, objroot)
1197
- @config = config
1198
- @srcdir = File.expand_path(srcroot)
1199
- @objdir = File.expand_path(objroot)
1200
- @currdir = '.'
1201
- end
1202
-
1203
- def inspect
1204
- "#<#{self.class} #{File.basename(@srcdir)}>"
1205
- end
1206
-
1207
- def noop(rel)
1208
- end
1209
-
1210
- #
1211
- # Hook Script API base methods
1212
- #
1213
-
1214
- def srcdir_root
1215
- @srcdir
1216
- end
1217
-
1218
- def objdir_root
1219
- @objdir
1220
- end
1221
-
1222
- def relpath
1223
- @currdir
1224
- end
1225
-
1226
- #
1227
- # Config Access
1228
- #
1229
-
1230
- # module FileOperations requires this
1231
- def verbose?
1232
- @config.verbose?
1233
- end
1234
-
1235
- # module FileOperations requires this
1236
- def no_harm?
1237
- @config.no_harm?
1238
- end
1239
-
1240
- def verbose_off
1241
- begin
1242
- save, @config.verbose = @config.verbose?, false
1243
- yield
1244
- ensure
1245
- @config.verbose = save
1246
- end
1247
- end
1248
-
1249
- #
1250
- # TASK config
1251
- #
1252
-
1253
- def exec_config
1254
- exec_task_traverse 'config'
1255
- end
1256
-
1257
- alias config_dir_bin noop
1258
- alias config_dir_lib noop
1259
-
1260
- def config_dir_ext(rel)
1261
- extconf if extdir?(curr_srcdir())
1262
- end
1263
-
1264
- alias config_dir_data noop
1265
- alias config_dir_conf noop
1266
- alias config_dir_man noop
1267
-
1268
- def extconf
1269
- ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
1270
- end
1271
-
1272
- #
1273
- # TASK setup
1274
- #
1275
-
1276
- def exec_setup
1277
- exec_task_traverse 'setup'
1278
- end
1279
-
1280
- def setup_dir_bin(rel)
1281
- files_of(curr_srcdir()).each do |fname|
1282
- update_shebang_line "#{curr_srcdir()}/#{fname}"
1283
- end
1284
- end
1285
-
1286
- alias setup_dir_lib noop
1287
-
1288
- def setup_dir_ext(rel)
1289
- make if extdir?(curr_srcdir())
1290
- end
1291
-
1292
- alias setup_dir_data noop
1293
- alias setup_dir_conf noop
1294
- alias setup_dir_man noop
1295
-
1296
- def update_shebang_line(path)
1297
- return if no_harm?
1298
- return if config('shebang') == 'never'
1299
- old = Shebang.load(path)
1300
- if old
1301
- $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
1302
- new = new_shebang(old)
1303
- return if new.to_s == old.to_s
1304
- else
1305
- return unless config('shebang') == 'all'
1306
- new = Shebang.new(config('rubypath'))
1307
- end
1308
- $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
1309
- open_atomic_writer(path) {|output|
1310
- File.open(path, 'rb') {|f|
1311
- f.gets if old # discard
1312
- output.puts new.to_s
1313
- output.print f.read
1314
- }
1315
- }
1316
- end
1317
-
1318
- def new_shebang(old)
1319
- if /\Aruby/ =~ File.basename(old.cmd)
1320
- Shebang.new(config('rubypath'), old.args)
1321
- elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
1322
- Shebang.new(config('rubypath'), old.args[1..-1])
1323
- else
1324
- return old unless config('shebang') == 'all'
1325
- Shebang.new(config('rubypath'))
1326
- end
1327
- end
1328
-
1329
- def open_atomic_writer(path, &block)
1330
- tmpfile = File.basename(path) + '.tmp'
1331
- begin
1332
- File.open(tmpfile, 'wb', &block)
1333
- File.rename tmpfile, File.basename(path)
1334
- ensure
1335
- File.unlink tmpfile if File.exist?(tmpfile)
1336
- end
1337
- end
1338
-
1339
- class Shebang
1340
- def Shebang.load(path)
1341
- line = nil
1342
- File.open(path) {|f|
1343
- line = f.gets
1344
- }
1345
- return nil unless /\A#!/ =~ line
1346
- parse(line)
1347
- end
1348
-
1349
- def Shebang.parse(line)
1350
- cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
1351
- new(cmd, args)
1352
- end
1353
-
1354
- def initialize(cmd, args = [])
1355
- @cmd = cmd
1356
- @args = args
1357
- end
1358
-
1359
- attr_reader :cmd
1360
- attr_reader :args
1361
-
1362
- def to_s
1363
- "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
1364
- end
1365
- end
1366
-
1367
- #
1368
- # TASK install
1369
- #
1370
-
1371
- def exec_install
1372
- rm_f "#{INSTALLED_MANIFEST}"
1373
- exec_task_traverse 'install'
1374
- end
1375
-
1376
- def install_dir_bin(rel)
1377
- install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
1378
- end
1379
-
1380
- def install_dir_lib(rel)
1381
- install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
1382
- end
1383
-
1384
- def install_dir_ext(rel)
1385
- return unless extdir?(curr_srcdir())
1386
- install_files rubyextentions('.'),
1387
- "#{config('sodir')}/#{File.dirname(rel)}",
1388
- 0555
1389
- end
1390
-
1391
- def install_dir_data(rel)
1392
- install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
1393
- end
1394
-
1395
- def install_dir_conf(rel)
1396
- # FIXME: should not remove current config files
1397
- # (rename previous file to .old/.org)
1398
- install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
1399
- end
1400
-
1401
- def install_dir_man(rel)
1402
- install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
1403
- end
1404
-
1405
- def install_files(list, dest, mode)
1406
- mkdir_p dest, @config.install_prefix
1407
- list.each do |fname|
1408
- install fname, dest, mode, @config.install_prefix
1409
- end
1410
- end
1411
-
1412
- def libfiles
1413
- glob_reject(%w(*.y *.output), targetfiles())
1414
- end
1415
-
1416
- def rubyextentions(dir)
1417
- ents = glob_select("*.#{@config.dllext}", targetfiles())
1418
- if ents.empty?
1419
- setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1420
- end
1421
- ents
1422
- end
1423
-
1424
- def targetfiles
1425
- mapdir(existfiles() - hookfiles())
1426
- end
1427
-
1428
- def mapdir(ents)
1429
- ents.map {|ent|
1430
- if File.exist?(ent)
1431
- then ent # objdir
1432
- else "#{curr_srcdir()}/#{ent}" # srcdir
1433
- end
1434
- }
1435
- end
1436
-
1437
- # picked up many entries from cvs-1.11.1/src/ignore.c
1438
- JUNK_FILES = %w(
1439
- core RCSLOG tags TAGS .make.state
1440
- .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1441
- *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1442
-
1443
- *.org *.in .*
1444
- )
1445
-
1446
- def existfiles
1447
- glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
1448
- end
1449
-
1450
- def hookfiles
1451
- %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1452
- %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1453
- }.flatten
1454
- end
1455
-
1456
- def glob_select(pat, ents)
1457
- re = globs2re([pat])
1458
- ents.select {|ent| re =~ ent }
1459
- end
1460
-
1461
- def glob_reject(pats, ents)
1462
- re = globs2re(pats)
1463
- ents.reject {|ent| re =~ ent }
1464
- end
1465
-
1466
- GLOB2REGEX = {
1467
- '.' => '\.',
1468
- '$' => '\$',
1469
- '#' => '\#',
1470
- '*' => '.*'
1471
- }
1472
-
1473
- def globs2re(pats)
1474
- /\A(?:#{
1475
- pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
1476
- })\z/
1477
- end
1478
-
1479
- #
1480
- # TASK test
1481
- #
1482
-
1483
- TESTDIR = 'test'
1484
-
1485
- def exec_test
1486
- unless File.directory?('test')
1487
- $stderr.puts 'no test in this package' if verbose?
1488
- return
1489
- end
1490
- $stderr.puts 'Running tests...' if verbose?
1491
- begin
1492
- require 'test/unit'
1493
- rescue LoadError
1494
- setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
1495
- end
1496
- runner = Test::Unit::AutoRunner.new(true)
1497
- runner.to_run << TESTDIR
1498
- runner.run
1499
- end
1500
-
1501
- #
1502
- # TASK clean
1503
- #
1504
-
1505
- def exec_clean
1506
- exec_task_traverse 'clean'
1507
- rm_f @config.savefile
1508
- rm_f "#{INSTALLED_MANIFEST}"
1509
- end
1510
-
1511
- alias clean_dir_bin noop
1512
- alias clean_dir_lib noop
1513
- alias clean_dir_data noop
1514
- alias clean_dir_conf noop
1515
- alias clean_dir_man noop
1516
-
1517
- def clean_dir_ext(rel)
1518
- return unless extdir?(curr_srcdir())
1519
- make 'clean' if File.file?('Makefile')
1520
- end
1521
-
1522
- #
1523
- # TASK distclean
1524
- #
1525
-
1526
- def exec_distclean
1527
- exec_task_traverse 'distclean'
1528
- rm_f @config.savefile
1529
- rm_f "#{INSTALLED_MANIFEST}"
1530
- end
1531
-
1532
- alias distclean_dir_bin noop
1533
- alias distclean_dir_lib noop
1534
-
1535
- def distclean_dir_ext(rel)
1536
- return unless extdir?(curr_srcdir())
1537
- make 'distclean' if File.file?('Makefile')
1538
- end
1539
-
1540
- alias distclean_dir_data noop
1541
- alias distclean_dir_conf noop
1542
- alias distclean_dir_man noop
1543
-
1544
- #
1545
- # Traversing
1546
- #
1547
-
1548
- def exec_task_traverse(task)
1549
- run_hook "pre-#{task}"
1550
- FILETYPES.each do |type|
1551
- if type == 'ext' and config('without-ext') == 'yes'
1552
- $stderr.puts 'skipping ext/* by user option' if verbose?
1553
- next
1554
- end
1555
- traverse task, type, "#{task}_dir_#{type}"
1556
- end
1557
- run_hook "post-#{task}"
1558
- end
1559
-
1560
- def traverse(task, rel, mid)
1561
- dive_into(rel) {
1562
- run_hook "pre-#{task}"
1563
- __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1564
- directories_of(curr_srcdir()).each do |d|
1565
- traverse task, "#{rel}/#{d}", mid
1566
- end
1567
- run_hook "post-#{task}"
1568
- }
1569
- end
1570
-
1571
- def dive_into(rel)
1572
- return unless File.dir?("#{@srcdir}/#{rel}")
1573
-
1574
- dir = File.basename(rel)
1575
- Dir.mkdir dir unless File.dir?(dir)
1576
- prevdir = Dir.pwd
1577
- Dir.chdir dir
1578
- $stderr.puts '---> ' + rel if verbose?
1579
- @currdir = rel
1580
- yield
1581
- Dir.chdir prevdir
1582
- $stderr.puts '<--- ' + rel if verbose?
1583
- @currdir = File.dirname(rel)
1584
- end
1585
-
1586
- def run_hook(id)
1587
- path = [ "#{curr_srcdir()}/#{id}",
1588
- "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
1589
- return unless path
1590
- begin
1591
- instance_eval File.read(path), path, 1
1592
- rescue
1593
- raise if $DEBUG
1594
- setup_rb_error "hook #{path} failed:\n" + $!.message
1595
- end
1596
- end
1597
-
1598
- end # class Installer
1599
-
1600
-
1601
- class SetupError < StandardError; end
1602
-
1603
- def setup_rb_error(msg)
1604
- raise SetupError, msg
1605
- end
1606
-
1607
- if $0 == __FILE__
1608
- begin
1609
- ToplevelInstaller.invoke
1610
- rescue SetupError
1611
- raise if $DEBUG
1612
- $stderr.puts $!.message
1613
- $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1614
- exit 1
1615
- end
1616
- end
1
+ #
2
+ # setup.rb
3
+ #
4
+ # Copyright (c) 2000-2005 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ #
10
+
11
+ unless Enumerable.method_defined?(:map) # Ruby 1.4.6
12
+ module Enumerable
13
+ alias map collect
14
+ end
15
+ end
16
+
17
+ unless File.respond_to?(:read) # Ruby 1.6
18
+ def File.read(fname)
19
+ open(fname) {|f|
20
+ return f.read
21
+ }
22
+ end
23
+ end
24
+
25
+ unless Errno.const_defined?(:ENOTEMPTY) # Windows?
26
+ module Errno
27
+ class ENOTEMPTY
28
+ # We do not raise this exception, implementation is not needed.
29
+ end
30
+ end
31
+ end
32
+
33
+ def File.binread(fname)
34
+ open(fname, 'rb') {|f|
35
+ return f.read
36
+ }
37
+ end
38
+
39
+ # for corrupted Windows' stat(2)
40
+ def File.dir?(path)
41
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
42
+ end
43
+
44
+
45
+ class ConfigTable
46
+
47
+ include Enumerable
48
+
49
+ def initialize(rbconfig)
50
+ @rbconfig = rbconfig
51
+ @items = []
52
+ @table = {}
53
+ # options
54
+ @install_prefix = nil
55
+ @config_opt = nil
56
+ @verbose = true
57
+ @no_harm = false
58
+ end
59
+
60
+ attr_accessor :install_prefix
61
+ attr_accessor :config_opt
62
+
63
+ attr_writer :verbose
64
+
65
+ def verbose?
66
+ @verbose
67
+ end
68
+
69
+ attr_writer :no_harm
70
+
71
+ def no_harm?
72
+ @no_harm
73
+ end
74
+
75
+ def [](key)
76
+ lookup(key).resolve(self)
77
+ end
78
+
79
+ def []=(key, val)
80
+ lookup(key).set val
81
+ end
82
+
83
+ def names
84
+ @items.map {|i| i.name }
85
+ end
86
+
87
+ def each(&block)
88
+ @items.each(&block)
89
+ end
90
+
91
+ def key?(name)
92
+ @table.key?(name)
93
+ end
94
+
95
+ def lookup(name)
96
+ @table[name] or setup_rb_error "no such config item: #{name}"
97
+ end
98
+
99
+ def add(item)
100
+ @items.push item
101
+ @table[item.name] = item
102
+ end
103
+
104
+ def remove(name)
105
+ item = lookup(name)
106
+ @items.delete_if {|i| i.name == name }
107
+ @table.delete_if {|name, i| i.name == name }
108
+ item
109
+ end
110
+
111
+ def load_script(path, inst = nil)
112
+ if File.file?(path)
113
+ MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
114
+ end
115
+ end
116
+
117
+ def savefile
118
+ '.config'
119
+ end
120
+
121
+ def load_savefile
122
+ begin
123
+ File.foreach(savefile()) do |line|
124
+ k, v = *line.split(/=/, 2)
125
+ self[k] = v.strip
126
+ end
127
+ rescue Errno::ENOENT
128
+ setup_rb_error $!.message + "\n#{File.basename($0)} config first"
129
+ end
130
+ end
131
+
132
+ def save
133
+ @items.each {|i| i.value }
134
+ File.open(savefile(), 'w') {|f|
135
+ @items.each do |i|
136
+ f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
137
+ end
138
+ }
139
+ end
140
+
141
+ def load_standard_entries
142
+ standard_entries(@rbconfig).each do |ent|
143
+ add ent
144
+ end
145
+ end
146
+
147
+ def standard_entries(rbconfig)
148
+ c = rbconfig
149
+
150
+ rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
151
+
152
+ major = c['MAJOR'].to_i
153
+ minor = c['MINOR'].to_i
154
+ teeny = c['TEENY'].to_i
155
+ version = "#{major}.#{minor}"
156
+
157
+ # ruby ver. >= 1.4.4?
158
+ newpath_p = ((major >= 2) or
159
+ ((major == 1) and
160
+ ((minor >= 5) or
161
+ ((minor == 4) and (teeny >= 4)))))
162
+
163
+ if c['rubylibdir']
164
+ # V > 1.6.3
165
+ libruby = "#{c['prefix']}/lib/ruby"
166
+ librubyver = c['rubylibdir']
167
+ librubyverarch = c['archdir']
168
+ siteruby = c['sitedir']
169
+ siterubyver = c['sitelibdir']
170
+ siterubyverarch = c['sitearchdir']
171
+ elsif newpath_p
172
+ # 1.4.4 <= V <= 1.6.3
173
+ libruby = "#{c['prefix']}/lib/ruby"
174
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
175
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
176
+ siteruby = c['sitedir']
177
+ siterubyver = "$siteruby/#{version}"
178
+ siterubyverarch = "$siterubyver/#{c['arch']}"
179
+ else
180
+ # V < 1.4.4
181
+ libruby = "#{c['prefix']}/lib/ruby"
182
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
183
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
184
+ siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
185
+ siterubyver = siteruby
186
+ siterubyverarch = "$siterubyver/#{c['arch']}"
187
+ end
188
+ parameterize = lambda {|path|
189
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
190
+ }
191
+
192
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
193
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
194
+ else
195
+ makeprog = 'make'
196
+ end
197
+
198
+ [
199
+ ExecItem.new('installdirs', 'std/site/home',
200
+ 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
201
+ {|val, table|
202
+ case val
203
+ when 'std'
204
+ table['rbdir'] = '$librubyver'
205
+ table['sodir'] = '$librubyverarch'
206
+ when 'site'
207
+ table['rbdir'] = '$siterubyver'
208
+ table['sodir'] = '$siterubyverarch'
209
+ when 'home'
210
+ setup_rb_error '$HOME was not set' unless ENV['HOME']
211
+ table['prefix'] = ENV['HOME']
212
+ table['rbdir'] = '$libdir/ruby'
213
+ table['sodir'] = '$libdir/ruby'
214
+ end
215
+ },
216
+ PathItem.new('prefix', 'path', c['prefix'],
217
+ 'path prefix of target environment'),
218
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
219
+ 'the directory for commands'),
220
+ PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
221
+ 'the directory for libraries'),
222
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
223
+ 'the directory for shared data'),
224
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
225
+ 'the directory for man pages'),
226
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
227
+ 'the directory for system configuration files'),
228
+ PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
229
+ 'the directory for local state data'),
230
+ PathItem.new('libruby', 'path', libruby,
231
+ 'the directory for ruby libraries'),
232
+ PathItem.new('librubyver', 'path', librubyver,
233
+ 'the directory for standard ruby libraries'),
234
+ PathItem.new('librubyverarch', 'path', librubyverarch,
235
+ 'the directory for standard ruby extensions'),
236
+ PathItem.new('siteruby', 'path', siteruby,
237
+ 'the directory for version-independent aux ruby libraries'),
238
+ PathItem.new('siterubyver', 'path', siterubyver,
239
+ 'the directory for aux ruby libraries'),
240
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
241
+ 'the directory for aux ruby binaries'),
242
+ PathItem.new('rbdir', 'path', '$siterubyver',
243
+ 'the directory for ruby scripts'),
244
+ PathItem.new('sodir', 'path', '$siterubyverarch',
245
+ 'the directory for ruby extentions'),
246
+ PathItem.new('rubypath', 'path', rubypath,
247
+ 'the path to set to #! line'),
248
+ ProgramItem.new('rubyprog', 'name', rubypath,
249
+ 'the ruby program using for installation'),
250
+ ProgramItem.new('makeprog', 'name', makeprog,
251
+ 'the make program to compile ruby extentions'),
252
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
253
+ 'shebang line (#!) editing mode'),
254
+ BoolItem.new('without-ext', 'yes/no', 'no',
255
+ 'does not compile/install ruby extentions')
256
+ ]
257
+ end
258
+ private :standard_entries
259
+
260
+ def load_multipackage_entries
261
+ multipackage_entries().each do |ent|
262
+ add ent
263
+ end
264
+ end
265
+
266
+ def multipackage_entries
267
+ [
268
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
269
+ 'package names that you want to install'),
270
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
271
+ 'package names that you do not want to install')
272
+ ]
273
+ end
274
+ private :multipackage_entries
275
+
276
+ ALIASES = {
277
+ 'std-ruby' => 'librubyver',
278
+ 'stdruby' => 'librubyver',
279
+ 'rubylibdir' => 'librubyver',
280
+ 'archdir' => 'librubyverarch',
281
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
282
+ 'site-ruby' => 'siterubyver', # For backward compatibility
283
+ 'bin-dir' => 'bindir',
284
+ 'bin-dir' => 'bindir',
285
+ 'rb-dir' => 'rbdir',
286
+ 'so-dir' => 'sodir',
287
+ 'data-dir' => 'datadir',
288
+ 'ruby-path' => 'rubypath',
289
+ 'ruby-prog' => 'rubyprog',
290
+ 'ruby' => 'rubyprog',
291
+ 'make-prog' => 'makeprog',
292
+ 'make' => 'makeprog'
293
+ }
294
+
295
+ def fixup
296
+ ALIASES.each do |ali, name|
297
+ @table[ali] = @table[name]
298
+ end
299
+ @items.freeze
300
+ @table.freeze
301
+ @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
302
+ end
303
+
304
+ def parse_opt(opt)
305
+ m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
306
+ m.to_a[1,2]
307
+ end
308
+
309
+ def dllext
310
+ @rbconfig['DLEXT']
311
+ end
312
+
313
+ def value_config?(name)
314
+ lookup(name).value?
315
+ end
316
+
317
+ class Item
318
+ def initialize(name, template, default, desc)
319
+ @name = name.freeze
320
+ @template = template
321
+ @value = default
322
+ @default = default
323
+ @description = desc
324
+ end
325
+
326
+ attr_reader :name
327
+ attr_reader :description
328
+
329
+ attr_accessor :default
330
+ alias help_default default
331
+
332
+ def help_opt
333
+ "--#{@name}=#{@template}"
334
+ end
335
+
336
+ def value?
337
+ true
338
+ end
339
+
340
+ def value
341
+ @value
342
+ end
343
+
344
+ def resolve(table)
345
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
346
+ end
347
+
348
+ def set(val)
349
+ @value = check(val)
350
+ end
351
+
352
+ private
353
+
354
+ def check(val)
355
+ setup_rb_error "config: --#{name} requires argument" unless val
356
+ val
357
+ end
358
+ end
359
+
360
+ class BoolItem < Item
361
+ def config_type
362
+ 'bool'
363
+ end
364
+
365
+ def help_opt
366
+ "--#{@name}"
367
+ end
368
+
369
+ private
370
+
371
+ def check(val)
372
+ return 'yes' unless val
373
+ case val
374
+ when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
375
+ when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
376
+ else
377
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
378
+ end
379
+ end
380
+ end
381
+
382
+ class PathItem < Item
383
+ def config_type
384
+ 'path'
385
+ end
386
+
387
+ private
388
+
389
+ def check(path)
390
+ setup_rb_error "config: --#{@name} requires argument" unless path
391
+ path[0,1] == '$' ? path : File.expand_path(path)
392
+ end
393
+ end
394
+
395
+ class ProgramItem < Item
396
+ def config_type
397
+ 'program'
398
+ end
399
+ end
400
+
401
+ class SelectItem < Item
402
+ def initialize(name, selection, default, desc)
403
+ super
404
+ @ok = selection.split('/')
405
+ end
406
+
407
+ def config_type
408
+ 'select'
409
+ end
410
+
411
+ private
412
+
413
+ def check(val)
414
+ unless @ok.include?(val.strip)
415
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
416
+ end
417
+ val.strip
418
+ end
419
+ end
420
+
421
+ class ExecItem < Item
422
+ def initialize(name, selection, desc, &block)
423
+ super name, selection, nil, desc
424
+ @ok = selection.split('/')
425
+ @action = block
426
+ end
427
+
428
+ def config_type
429
+ 'exec'
430
+ end
431
+
432
+ def value?
433
+ false
434
+ end
435
+
436
+ def resolve(table)
437
+ setup_rb_error "$#{name()} wrongly used as option value"
438
+ end
439
+
440
+ undef set
441
+
442
+ def evaluate(val, table)
443
+ v = val.strip.downcase
444
+ unless @ok.include?(v)
445
+ setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
446
+ end
447
+ @action.call v, table
448
+ end
449
+ end
450
+
451
+ class PackageSelectionItem < Item
452
+ def initialize(name, template, default, help_default, desc)
453
+ super name, template, default, desc
454
+ @help_default = help_default
455
+ end
456
+
457
+ attr_reader :help_default
458
+
459
+ def config_type
460
+ 'package'
461
+ end
462
+
463
+ private
464
+
465
+ def check(val)
466
+ unless File.dir?("packages/#{val}")
467
+ setup_rb_error "config: no such package: #{val}"
468
+ end
469
+ val
470
+ end
471
+ end
472
+
473
+ class MetaConfigEnvironment
474
+ def initialize(config, installer)
475
+ @config = config
476
+ @installer = installer
477
+ end
478
+
479
+ def config_names
480
+ @config.names
481
+ end
482
+
483
+ def config?(name)
484
+ @config.key?(name)
485
+ end
486
+
487
+ def bool_config?(name)
488
+ @config.lookup(name).config_type == 'bool'
489
+ end
490
+
491
+ def path_config?(name)
492
+ @config.lookup(name).config_type == 'path'
493
+ end
494
+
495
+ def value_config?(name)
496
+ @config.lookup(name).config_type != 'exec'
497
+ end
498
+
499
+ def add_config(item)
500
+ @config.add item
501
+ end
502
+
503
+ def add_bool_config(name, default, desc)
504
+ @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
505
+ end
506
+
507
+ def add_path_config(name, default, desc)
508
+ @config.add PathItem.new(name, 'path', default, desc)
509
+ end
510
+
511
+ def set_config_default(name, default)
512
+ @config.lookup(name).default = default
513
+ end
514
+
515
+ def remove_config(name)
516
+ @config.remove(name)
517
+ end
518
+
519
+ # For only multipackage
520
+ def packages
521
+ raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
522
+ @installer.packages
523
+ end
524
+
525
+ # For only multipackage
526
+ def declare_packages(list)
527
+ raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
528
+ @installer.packages = list
529
+ end
530
+ end
531
+
532
+ end # class ConfigTable
533
+
534
+
535
+ # This module requires: #verbose?, #no_harm?
536
+ module FileOperations
537
+
538
+ def mkdir_p(dirname, prefix = nil)
539
+ dirname = prefix + File.expand_path(dirname) if prefix
540
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
541
+ return if no_harm?
542
+
543
+ # Does not check '/', it's too abnormal.
544
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
545
+ if /\A[a-z]:\z/i =~ dirs[0]
546
+ disk = dirs.shift
547
+ dirs[0] = disk + dirs[0]
548
+ end
549
+ dirs.each_index do |idx|
550
+ path = dirs[0..idx].join('')
551
+ Dir.mkdir path unless File.dir?(path)
552
+ end
553
+ end
554
+
555
+ def rm_f(path)
556
+ $stderr.puts "rm -f #{path}" if verbose?
557
+ return if no_harm?
558
+ force_remove_file path
559
+ end
560
+
561
+ def rm_rf(path)
562
+ $stderr.puts "rm -rf #{path}" if verbose?
563
+ return if no_harm?
564
+ remove_tree path
565
+ end
566
+
567
+ def remove_tree(path)
568
+ if File.symlink?(path)
569
+ remove_file path
570
+ elsif File.dir?(path)
571
+ remove_tree0 path
572
+ else
573
+ force_remove_file path
574
+ end
575
+ end
576
+
577
+ def remove_tree0(path)
578
+ Dir.foreach(path) do |ent|
579
+ next if ent == '.'
580
+ next if ent == '..'
581
+ entpath = "#{path}/#{ent}"
582
+ if File.symlink?(entpath)
583
+ remove_file entpath
584
+ elsif File.dir?(entpath)
585
+ remove_tree0 entpath
586
+ else
587
+ force_remove_file entpath
588
+ end
589
+ end
590
+ begin
591
+ Dir.rmdir path
592
+ rescue Errno::ENOTEMPTY
593
+ # directory may not be empty
594
+ end
595
+ end
596
+
597
+ def move_file(src, dest)
598
+ force_remove_file dest
599
+ begin
600
+ File.rename src, dest
601
+ rescue
602
+ File.open(dest, 'wb') {|f|
603
+ f.write File.binread(src)
604
+ }
605
+ File.chmod File.stat(src).mode, dest
606
+ File.unlink src
607
+ end
608
+ end
609
+
610
+ def force_remove_file(path)
611
+ begin
612
+ remove_file path
613
+ rescue
614
+ end
615
+ end
616
+
617
+ def remove_file(path)
618
+ File.chmod 0777, path
619
+ File.unlink path
620
+ end
621
+
622
+ def install(from, dest, mode, prefix = nil)
623
+ $stderr.puts "install #{from} #{dest}" if verbose?
624
+ return if no_harm?
625
+
626
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
627
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
628
+ str = File.binread(from)
629
+ if diff?(str, realdest)
630
+ verbose_off {
631
+ rm_f realdest if File.exist?(realdest)
632
+ }
633
+ File.open(realdest, 'wb') {|f|
634
+ f.write str
635
+ }
636
+ File.chmod mode, realdest
637
+
638
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
639
+ if prefix
640
+ f.puts realdest.sub(prefix, '')
641
+ else
642
+ f.puts realdest
643
+ end
644
+ }
645
+ end
646
+ end
647
+
648
+ def diff?(new_content, path)
649
+ return true unless File.exist?(path)
650
+ new_content != File.binread(path)
651
+ end
652
+
653
+ def command(*args)
654
+ $stderr.puts args.join(' ') if verbose?
655
+ system(*args) or raise RuntimeError,
656
+ "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
657
+ end
658
+
659
+ def ruby(*args)
660
+ command config('rubyprog'), *args
661
+ end
662
+
663
+ def make(task = nil)
664
+ command(*[config('makeprog'), task].compact)
665
+ end
666
+
667
+ def extdir?(dir)
668
+ File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
669
+ end
670
+
671
+ def files_of(dir)
672
+ Dir.open(dir) {|d|
673
+ return d.select {|ent| File.file?("#{dir}/#{ent}") }
674
+ }
675
+ end
676
+
677
+ DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
678
+
679
+ def directories_of(dir)
680
+ Dir.open(dir) {|d|
681
+ return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
682
+ }
683
+ end
684
+
685
+ end
686
+
687
+
688
+ # This module requires: #srcdir_root, #objdir_root, #relpath
689
+ module HookScriptAPI
690
+
691
+ def get_config(key)
692
+ @config[key]
693
+ end
694
+
695
+ alias config get_config
696
+
697
+ # obsolete: use metaconfig to change configuration
698
+ def set_config(key, val)
699
+ @config[key] = val
700
+ end
701
+
702
+ #
703
+ # srcdir/objdir (works only in the package directory)
704
+ #
705
+
706
+ def curr_srcdir
707
+ "#{srcdir_root()}/#{relpath()}"
708
+ end
709
+
710
+ def curr_objdir
711
+ "#{objdir_root()}/#{relpath()}"
712
+ end
713
+
714
+ def srcfile(path)
715
+ "#{curr_srcdir()}/#{path}"
716
+ end
717
+
718
+ def srcexist?(path)
719
+ File.exist?(srcfile(path))
720
+ end
721
+
722
+ def srcdirectory?(path)
723
+ File.dir?(srcfile(path))
724
+ end
725
+
726
+ def srcfile?(path)
727
+ File.file?(srcfile(path))
728
+ end
729
+
730
+ def srcentries(path = '.')
731
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
732
+ return d.to_a - %w(. ..)
733
+ }
734
+ end
735
+
736
+ def srcfiles(path = '.')
737
+ srcentries(path).select {|fname|
738
+ File.file?(File.join(curr_srcdir(), path, fname))
739
+ }
740
+ end
741
+
742
+ def srcdirectories(path = '.')
743
+ srcentries(path).select {|fname|
744
+ File.dir?(File.join(curr_srcdir(), path, fname))
745
+ }
746
+ end
747
+
748
+ end
749
+
750
+
751
+ class ToplevelInstaller
752
+
753
+ Version = '3.4.1'
754
+ Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
755
+
756
+ TASKS = [
757
+ [ 'all', 'do config, setup, then install' ],
758
+ [ 'config', 'saves your configurations' ],
759
+ [ 'show', 'shows current configuration' ],
760
+ [ 'setup', 'compiles ruby extentions and others' ],
761
+ [ 'install', 'installs files' ],
762
+ [ 'test', 'run all tests in test/' ],
763
+ [ 'clean', "does `make clean' for each extention" ],
764
+ [ 'distclean',"does `make distclean' for each extention" ]
765
+ ]
766
+
767
+ def ToplevelInstaller.invoke
768
+ config = ConfigTable.new(load_rbconfig())
769
+ config.load_standard_entries
770
+ config.load_multipackage_entries if multipackage?
771
+ config.fixup
772
+ klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
773
+ klass.new(File.dirname($0), config).invoke
774
+ end
775
+
776
+ def ToplevelInstaller.multipackage?
777
+ File.dir?(File.dirname($0) + '/packages')
778
+ end
779
+
780
+ def ToplevelInstaller.load_rbconfig
781
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
782
+ ARGV.delete(arg)
783
+ load File.expand_path(arg.split(/=/, 2)[1])
784
+ $".push 'rbconfig.rb'
785
+ else
786
+ require 'rbconfig'
787
+ end
788
+ ::Config::CONFIG
789
+ end
790
+
791
+ def initialize(ardir_root, config)
792
+ @ardir = File.expand_path(ardir_root)
793
+ @config = config
794
+ # cache
795
+ @valid_task_re = nil
796
+ end
797
+
798
+ def config(key)
799
+ @config[key]
800
+ end
801
+
802
+ def inspect
803
+ "#<#{self.class} #{__id__()}>"
804
+ end
805
+
806
+ def invoke
807
+ run_metaconfigs
808
+ case task = parsearg_global()
809
+ when nil, 'all'
810
+ parsearg_config
811
+ init_installers
812
+ exec_config
813
+ exec_setup
814
+ exec_install
815
+ else
816
+ case task
817
+ when 'config', 'test'
818
+ ;
819
+ when 'clean', 'distclean'
820
+ @config.load_savefile if File.exist?(@config.savefile)
821
+ else
822
+ @config.load_savefile
823
+ end
824
+ __send__ "parsearg_#{task}"
825
+ init_installers
826
+ __send__ "exec_#{task}"
827
+ end
828
+ end
829
+
830
+ def run_metaconfigs
831
+ @config.load_script "#{@ardir}/metaconfig"
832
+ end
833
+
834
+ def init_installers
835
+ @installer = Installer.new(@config, @ardir, File.expand_path('.'))
836
+ end
837
+
838
+ #
839
+ # Hook Script API bases
840
+ #
841
+
842
+ def srcdir_root
843
+ @ardir
844
+ end
845
+
846
+ def objdir_root
847
+ '.'
848
+ end
849
+
850
+ def relpath
851
+ '.'
852
+ end
853
+
854
+ #
855
+ # Option Parsing
856
+ #
857
+
858
+ def parsearg_global
859
+ while arg = ARGV.shift
860
+ case arg
861
+ when /\A\w+\z/
862
+ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
863
+ return arg
864
+ when '-q', '--quiet'
865
+ @config.verbose = false
866
+ when '--verbose'
867
+ @config.verbose = true
868
+ when '--help'
869
+ print_usage $stdout
870
+ exit 0
871
+ when '--version'
872
+ puts "#{File.basename($0)} version #{Version}"
873
+ exit 0
874
+ when '--copyright'
875
+ puts Copyright
876
+ exit 0
877
+ else
878
+ setup_rb_error "unknown global option '#{arg}'"
879
+ end
880
+ end
881
+ nil
882
+ end
883
+
884
+ def valid_task?(t)
885
+ valid_task_re() =~ t
886
+ end
887
+
888
+ def valid_task_re
889
+ @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
890
+ end
891
+
892
+ def parsearg_no_options
893
+ unless ARGV.empty?
894
+ task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
895
+ setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
896
+ end
897
+ end
898
+
899
+ alias parsearg_show parsearg_no_options
900
+ alias parsearg_setup parsearg_no_options
901
+ alias parsearg_test parsearg_no_options
902
+ alias parsearg_clean parsearg_no_options
903
+ alias parsearg_distclean parsearg_no_options
904
+
905
+ def parsearg_config
906
+ evalopt = []
907
+ set = []
908
+ @config.config_opt = []
909
+ while i = ARGV.shift
910
+ if /\A--?\z/ =~ i
911
+ @config.config_opt = ARGV.dup
912
+ break
913
+ end
914
+ name, value = *@config.parse_opt(i)
915
+ if @config.value_config?(name)
916
+ @config[name] = value
917
+ else
918
+ evalopt.push [name, value]
919
+ end
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