reidiculous-actionwebservice-client 3.0.4

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 (179) hide show
  1. data/CHANGELOG +320 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +180 -0
  5. data/TODO +32 -0
  6. data/lib/action_web_service.rb +71 -0
  7. data/lib/action_web_service/api.rb +297 -0
  8. data/lib/action_web_service/base.rb +38 -0
  9. data/lib/action_web_service/casting.rb +149 -0
  10. data/lib/action_web_service/client.rb +3 -0
  11. data/lib/action_web_service/client/base.rb +28 -0
  12. data/lib/action_web_service/client/soap_client.rb +113 -0
  13. data/lib/action_web_service/client/xmlrpc_client.rb +58 -0
  14. data/lib/action_web_service/container.rb +3 -0
  15. data/lib/action_web_service/container/action_controller_container.rb +93 -0
  16. data/lib/action_web_service/container/delegated_container.rb +86 -0
  17. data/lib/action_web_service/container/direct_container.rb +69 -0
  18. data/lib/action_web_service/dispatcher.rb +2 -0
  19. data/lib/action_web_service/dispatcher/abstract.rb +207 -0
  20. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +379 -0
  21. data/lib/action_web_service/invocation.rb +202 -0
  22. data/lib/action_web_service/protocol.rb +4 -0
  23. data/lib/action_web_service/protocol/abstract.rb +115 -0
  24. data/lib/action_web_service/protocol/discovery.rb +37 -0
  25. data/lib/action_web_service/protocol/soap_protocol.rb +176 -0
  26. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +242 -0
  27. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +122 -0
  28. data/lib/action_web_service/scaffolding.rb +281 -0
  29. data/lib/action_web_service/soap/attachment.rb +107 -0
  30. data/lib/action_web_service/soap/baseData.rb +942 -0
  31. data/lib/action_web_service/soap/element.rb +258 -0
  32. data/lib/action_web_service/soap/encodingstyle/aspDotNetHandler.rb +213 -0
  33. data/lib/action_web_service/soap/encodingstyle/handler.rb +100 -0
  34. data/lib/action_web_service/soap/encodingstyle/literalHandler.rb +226 -0
  35. data/lib/action_web_service/soap/encodingstyle/soapHandler.rb +582 -0
  36. data/lib/action_web_service/soap/generator.rb +268 -0
  37. data/lib/action_web_service/soap/header/handler.rb +57 -0
  38. data/lib/action_web_service/soap/header/handlerset.rb +70 -0
  39. data/lib/action_web_service/soap/header/simplehandler.rb +44 -0
  40. data/lib/action_web_service/soap/httpconfigloader.rb +119 -0
  41. data/lib/action_web_service/soap/mapping.rb +10 -0
  42. data/lib/action_web_service/soap/mapping/factory.rb +355 -0
  43. data/lib/action_web_service/soap/mapping/mapping.rb +381 -0
  44. data/lib/action_web_service/soap/mapping/registry.rb +541 -0
  45. data/lib/action_web_service/soap/mapping/rubytypeFactory.rb +475 -0
  46. data/lib/action_web_service/soap/mapping/typeMap.rb +50 -0
  47. data/lib/action_web_service/soap/mapping/wsdlencodedregistry.rb +280 -0
  48. data/lib/action_web_service/soap/mapping/wsdlliteralregistry.rb +418 -0
  49. data/lib/action_web_service/soap/marshal.rb +59 -0
  50. data/lib/action_web_service/soap/mimemessage.rb +240 -0
  51. data/lib/action_web_service/soap/netHttpClient.rb +190 -0
  52. data/lib/action_web_service/soap/parser.rb +251 -0
  53. data/lib/action_web_service/soap/processor.rb +66 -0
  54. data/lib/action_web_service/soap/property.rb +333 -0
  55. data/lib/action_web_service/soap/rpc/cgistub.rb +206 -0
  56. data/lib/action_web_service/soap/rpc/driver.rb +254 -0
  57. data/lib/action_web_service/soap/rpc/element.rb +325 -0
  58. data/lib/action_web_service/soap/rpc/httpserver.rb +129 -0
  59. data/lib/action_web_service/soap/rpc/proxy.rb +497 -0
  60. data/lib/action_web_service/soap/rpc/router.rb +594 -0
  61. data/lib/action_web_service/soap/rpc/rpc.rb +25 -0
  62. data/lib/action_web_service/soap/rpc/soaplet.rb +162 -0
  63. data/lib/action_web_service/soap/rpc/standaloneServer.rb +43 -0
  64. data/lib/action_web_service/soap/soap.rb +140 -0
  65. data/lib/action_web_service/soap/streamHandler.rb +229 -0
  66. data/lib/action_web_service/soap/wsdlDriver.rb +575 -0
  67. data/lib/action_web_service/struct.rb +64 -0
  68. data/lib/action_web_service/support/class_inheritable_options.rb +28 -0
  69. data/lib/action_web_service/support/signature_types.rb +227 -0
  70. data/lib/action_web_service/test_invoke.rb +110 -0
  71. data/lib/action_web_service/version.rb +9 -0
  72. data/lib/action_web_service/wsdl/binding.rb +65 -0
  73. data/lib/action_web_service/wsdl/data.rb +64 -0
  74. data/lib/action_web_service/wsdl/definitions.rb +250 -0
  75. data/lib/action_web_service/wsdl/documentation.rb +32 -0
  76. data/lib/action_web_service/wsdl/import.rb +80 -0
  77. data/lib/action_web_service/wsdl/importer.rb +38 -0
  78. data/lib/action_web_service/wsdl/info.rb +39 -0
  79. data/lib/action_web_service/wsdl/message.rb +54 -0
  80. data/lib/action_web_service/wsdl/operation.rb +130 -0
  81. data/lib/action_web_service/wsdl/operationBinding.rb +108 -0
  82. data/lib/action_web_service/wsdl/param.rb +85 -0
  83. data/lib/action_web_service/wsdl/parser.rb +163 -0
  84. data/lib/action_web_service/wsdl/part.rb +52 -0
  85. data/lib/action_web_service/wsdl/port.rb +84 -0
  86. data/lib/action_web_service/wsdl/portType.rb +73 -0
  87. data/lib/action_web_service/wsdl/service.rb +61 -0
  88. data/lib/action_web_service/wsdl/soap/address.rb +40 -0
  89. data/lib/action_web_service/wsdl/soap/binding.rb +49 -0
  90. data/lib/action_web_service/wsdl/soap/body.rb +56 -0
  91. data/lib/action_web_service/wsdl/soap/cgiStubCreator.rb +76 -0
  92. data/lib/action_web_service/wsdl/soap/classDefCreator.rb +314 -0
  93. data/lib/action_web_service/wsdl/soap/classDefCreatorSupport.rb +126 -0
  94. data/lib/action_web_service/wsdl/soap/clientSkeltonCreator.rb +78 -0
  95. data/lib/action_web_service/wsdl/soap/complexType.rb +161 -0
  96. data/lib/action_web_service/wsdl/soap/data.rb +42 -0
  97. data/lib/action_web_service/wsdl/soap/definitions.rb +149 -0
  98. data/lib/action_web_service/wsdl/soap/driverCreator.rb +95 -0
  99. data/lib/action_web_service/wsdl/soap/element.rb +28 -0
  100. data/lib/action_web_service/wsdl/soap/fault.rb +56 -0
  101. data/lib/action_web_service/wsdl/soap/header.rb +86 -0
  102. data/lib/action_web_service/wsdl/soap/headerfault.rb +56 -0
  103. data/lib/action_web_service/wsdl/soap/mappingRegistryCreator.rb +92 -0
  104. data/lib/action_web_service/wsdl/soap/methodDefCreator.rb +228 -0
  105. data/lib/action_web_service/wsdl/soap/operation.rb +122 -0
  106. data/lib/action_web_service/wsdl/soap/servantSkeltonCreator.rb +67 -0
  107. data/lib/action_web_service/wsdl/soap/standaloneServerStubCreator.rb +85 -0
  108. data/lib/action_web_service/wsdl/soap/wsdl2ruby.rb +176 -0
  109. data/lib/action_web_service/wsdl/types.rb +43 -0
  110. data/lib/action_web_service/wsdl/wsdl.rb +23 -0
  111. data/lib/action_web_service/wsdl/xmlSchema/all.rb +69 -0
  112. data/lib/action_web_service/wsdl/xmlSchema/annotation.rb +34 -0
  113. data/lib/action_web_service/wsdl/xmlSchema/any.rb +56 -0
  114. data/lib/action_web_service/wsdl/xmlSchema/attribute.rb +127 -0
  115. data/lib/action_web_service/wsdl/xmlSchema/choice.rb +69 -0
  116. data/lib/action_web_service/wsdl/xmlSchema/complexContent.rb +92 -0
  117. data/lib/action_web_service/wsdl/xmlSchema/complexType.rb +139 -0
  118. data/lib/action_web_service/wsdl/xmlSchema/content.rb +96 -0
  119. data/lib/action_web_service/wsdl/xmlSchema/data.rb +80 -0
  120. data/lib/action_web_service/wsdl/xmlSchema/element.rb +154 -0
  121. data/lib/action_web_service/wsdl/xmlSchema/enumeration.rb +36 -0
  122. data/lib/action_web_service/wsdl/xmlSchema/import.rb +65 -0
  123. data/lib/action_web_service/wsdl/xmlSchema/importer.rb +87 -0
  124. data/lib/action_web_service/wsdl/xmlSchema/include.rb +54 -0
  125. data/lib/action_web_service/wsdl/xmlSchema/length.rb +35 -0
  126. data/lib/action_web_service/wsdl/xmlSchema/parser.rb +166 -0
  127. data/lib/action_web_service/wsdl/xmlSchema/pattern.rb +36 -0
  128. data/lib/action_web_service/wsdl/xmlSchema/schema.rb +143 -0
  129. data/lib/action_web_service/wsdl/xmlSchema/sequence.rb +69 -0
  130. data/lib/action_web_service/wsdl/xmlSchema/simpleContent.rb +65 -0
  131. data/lib/action_web_service/wsdl/xmlSchema/simpleExtension.rb +54 -0
  132. data/lib/action_web_service/wsdl/xmlSchema/simpleRestriction.rb +73 -0
  133. data/lib/action_web_service/wsdl/xmlSchema/simpleType.rb +73 -0
  134. data/lib/action_web_service/wsdl/xmlSchema/unique.rb +34 -0
  135. data/lib/action_web_service/wsdl/xmlSchema/xsd2ruby.rb +107 -0
  136. data/lib/action_web_service/xsd/charset.rb +187 -0
  137. data/lib/action_web_service/xsd/codegen.rb +12 -0
  138. data/lib/action_web_service/xsd/codegen/classdef.rb +203 -0
  139. data/lib/action_web_service/xsd/codegen/commentdef.rb +34 -0
  140. data/lib/action_web_service/xsd/codegen/gensupport.rb +166 -0
  141. data/lib/action_web_service/xsd/codegen/methoddef.rb +63 -0
  142. data/lib/action_web_service/xsd/codegen/moduledef.rb +191 -0
  143. data/lib/action_web_service/xsd/datatypes.rb +1269 -0
  144. data/lib/action_web_service/xsd/datatypes1999.rb +20 -0
  145. data/lib/action_web_service/xsd/iconvcharset.rb +33 -0
  146. data/lib/action_web_service/xsd/mapping.rb +42 -0
  147. data/lib/action_web_service/xsd/namedelements.rb +95 -0
  148. data/lib/action_web_service/xsd/ns.rb +140 -0
  149. data/lib/action_web_service/xsd/qname.rb +78 -0
  150. data/lib/action_web_service/xsd/xmlparser.rb +61 -0
  151. data/lib/action_web_service/xsd/xmlparser/parser.rb +96 -0
  152. data/lib/action_web_service/xsd/xmlparser/rexmlparser.rb +54 -0
  153. data/lib/action_web_service/xsd/xmlparser/xmlparser.rb +50 -0
  154. data/lib/action_web_service/xsd/xmlparser/xmlscanner.rb +147 -0
  155. data/lib/actionwebservice.rb +1 -0
  156. data/setup.rb +1379 -0
  157. data/test/abstract_client.rb +183 -0
  158. data/test/abstract_dispatcher.rb +548 -0
  159. data/test/abstract_unit.rb +45 -0
  160. data/test/api_test.rb +103 -0
  161. data/test/apis/auto_load_api.rb +3 -0
  162. data/test/apis/broken_auto_load_api.rb +2 -0
  163. data/test/base_test.rb +42 -0
  164. data/test/casting_test.rb +95 -0
  165. data/test/client_soap_test.rb +156 -0
  166. data/test/client_xmlrpc_test.rb +153 -0
  167. data/test/container_test.rb +73 -0
  168. data/test/dispatcher_action_controller_soap_test.rb +139 -0
  169. data/test/dispatcher_action_controller_xmlrpc_test.rb +59 -0
  170. data/test/fixtures/db_definitions/mysql.sql +8 -0
  171. data/test/fixtures/db_definitions/sqlite3.sql +8 -0
  172. data/test/fixtures/users.yml +12 -0
  173. data/test/gencov +3 -0
  174. data/test/invocation_test.rb +185 -0
  175. data/test/run +6 -0
  176. data/test/scaffolded_controller_test.rb +146 -0
  177. data/test/struct_test.rb +52 -0
  178. data/test/test_invoke_test.rb +112 -0
  179. metadata +265 -0
@@ -0,0 +1,96 @@
1
+ # XSD4R - XML Instance parser library.
2
+ # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ require 'action_web_service/xsd/qname'
10
+ require 'action_web_service/xsd/ns'
11
+ require 'action_web_service/xsd/charset'
12
+
13
+
14
+ module XSD
15
+ module XMLParser
16
+
17
+
18
+ class Parser
19
+ class ParseError < Error; end
20
+ class FormatDecodeError < ParseError; end
21
+ class UnknownElementError < FormatDecodeError; end
22
+ class UnknownAttributeError < FormatDecodeError; end
23
+ class UnexpectedElementError < FormatDecodeError; end
24
+ class ElementConstraintError < FormatDecodeError; end
25
+
26
+ @@parser_factory = nil
27
+
28
+ def self.factory
29
+ @@parser_factory
30
+ end
31
+
32
+ def self.create_parser(host, opt = {})
33
+ @@parser_factory.new(host, opt)
34
+ end
35
+
36
+ def self.add_factory(factory)
37
+ if $DEBUG
38
+ puts "Set #{ factory } as XML processor."
39
+ end
40
+ @@parser_factory = factory
41
+ end
42
+
43
+ public
44
+
45
+ attr_accessor :charset
46
+
47
+ def initialize(host, opt = {})
48
+ @host = host
49
+ @charset = opt[:charset] || nil
50
+ end
51
+
52
+ def parse(string_or_readable)
53
+ @textbuf = ''
54
+ prologue
55
+ do_parse(string_or_readable)
56
+ epilogue
57
+ end
58
+
59
+ private
60
+
61
+ def do_parse(string_or_readable)
62
+ raise NotImplementError.new(
63
+ 'Method do_parse must be defined in derived class.')
64
+ end
65
+
66
+ def start_element(name, attrs)
67
+ @host.start_element(name, attrs)
68
+ end
69
+
70
+ def characters(text)
71
+ @host.characters(text)
72
+ end
73
+
74
+ def end_element(name)
75
+ @host.end_element(name)
76
+ end
77
+
78
+ def prologue
79
+ end
80
+
81
+ def epilogue
82
+ end
83
+
84
+ def xmldecl_encoding=(charset)
85
+ if @charset.nil?
86
+ @charset = charset
87
+ else
88
+ # Definition in a stream (like HTTP) has a priority.
89
+ p "encoding definition: #{ charset } is ignored." if $DEBUG
90
+ end
91
+ end
92
+ end
93
+
94
+
95
+ end
96
+ end
@@ -0,0 +1,54 @@
1
+ # XSD4R - REXMLParser XML parser library.
2
+ # Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ require 'action_web_service/xsd/xmlparser'
10
+ require 'rexml/streamlistener'
11
+ require 'rexml/document'
12
+
13
+
14
+ module XSD
15
+ module XMLParser
16
+
17
+
18
+ class REXMLParser < XSD::XMLParser::Parser
19
+ include REXML::StreamListener
20
+
21
+ def do_parse(string_or_readable)
22
+ source = nil
23
+ source = REXML::SourceFactory.create_from(string_or_readable)
24
+ source.encoding = charset if charset
25
+ # Listener passes a String in utf-8.
26
+ @charset = 'utf-8'
27
+ REXML::Document.parse_stream(source, self)
28
+ end
29
+
30
+ def epilogue
31
+ end
32
+
33
+ def tag_start(name, attrs)
34
+ start_element(name, attrs)
35
+ end
36
+
37
+ def tag_end(name)
38
+ end_element(name)
39
+ end
40
+
41
+ def text(text)
42
+ characters(text)
43
+ end
44
+
45
+ def xmldecl(version, encoding, standalone)
46
+ # Version should be checked.
47
+ end
48
+
49
+ add_factory(self)
50
+ end
51
+
52
+
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ # XSD4R - XMLParser XML parser library.
2
+ # Copyright (C) 2001, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ require 'action_web_service/xsd/xmlparser'
10
+ require 'xml/parser'
11
+
12
+
13
+ module XSD
14
+ module XMLParser
15
+
16
+
17
+ class XMLParser < XSD::XMLParser::Parser
18
+ class Listener < XML::Parser
19
+ begin
20
+ require 'xml/encoding-ja'
21
+ include XML::Encoding_ja
22
+ rescue LoadError
23
+ # uconv may not be installed.
24
+ end
25
+ end
26
+
27
+ def do_parse(string_or_readable)
28
+ # XMLParser passes a String in utf-8.
29
+ @charset = 'utf-8'
30
+ @parser = Listener.new
31
+ @parser.parse(string_or_readable) do |type, name, data|
32
+ case type
33
+ when XML::Parser::START_ELEM
34
+ start_element(name, data)
35
+ when XML::Parser::END_ELEM
36
+ end_element(name)
37
+ when XML::Parser::CDATA
38
+ characters(data)
39
+ else
40
+ raise FormatDecodeError.new("Unexpected XML: #{ type }/#{ name }/#{ data }.")
41
+ end
42
+ end
43
+ end
44
+
45
+ add_factory(self)
46
+ end
47
+
48
+
49
+ end
50
+ end
@@ -0,0 +1,147 @@
1
+ # XSD4R - XMLScan XML parser library.
2
+ # Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ require 'action_web_service/xsd/xmlparser'
10
+ require 'xmlscan/scanner'
11
+
12
+
13
+ module XSD
14
+ module XMLParser
15
+
16
+
17
+ class XMLScanner < XSD::XMLParser::Parser
18
+ include XMLScan::Visitor
19
+
20
+ def do_parse(string_or_readable)
21
+ @attrs = {}
22
+ @curattr = nil
23
+ @scanner = XMLScan::XMLScanner.new(self)
24
+ @scanner.kcode = XSD::Charset.charset_str(charset) if charset
25
+ @scanner.parse(string_or_readable)
26
+ end
27
+
28
+ def scanner_kcode=(charset)
29
+ @scanner.kcode = XSD::Charset.charset_str(charset) if charset
30
+ self.xmldecl_encoding = charset
31
+ end
32
+
33
+ ENTITY_REF_MAP = {
34
+ 'lt' => '<',
35
+ 'gt' => '>',
36
+ 'amp' => '&',
37
+ 'quot' => '"',
38
+ 'apos' => '\''
39
+ }
40
+
41
+ def parse_error(msg)
42
+ raise ParseError.new(msg)
43
+ end
44
+
45
+ def wellformed_error(msg)
46
+ raise NotWellFormedError.new(msg)
47
+ end
48
+
49
+ def valid_error(msg)
50
+ raise NotValidError.new(msg)
51
+ end
52
+
53
+ def warning(msg)
54
+ p msg if $DEBUG
55
+ end
56
+
57
+ # def on_xmldecl; end
58
+
59
+ def on_xmldecl_version(str)
60
+ # 1.0 expected.
61
+ end
62
+
63
+ def on_xmldecl_encoding(str)
64
+ self.scanner_kcode = str
65
+ end
66
+
67
+ # def on_xmldecl_standalone(str); end
68
+
69
+ # def on_xmldecl_other(name, value); end
70
+
71
+ # def on_xmldecl_end; end
72
+
73
+ # def on_doctype(root, pubid, sysid); end
74
+
75
+ # def on_prolog_space(str); end
76
+
77
+ # def on_comment(str); end
78
+
79
+ # def on_pi(target, pi); end
80
+
81
+ def on_chardata(str)
82
+ characters(str)
83
+ end
84
+
85
+ # def on_cdata(str); end
86
+
87
+ def on_etag(name)
88
+ end_element(name)
89
+ end
90
+
91
+ def on_entityref(ref)
92
+ characters(ENTITY_REF_MAP[ref])
93
+ end
94
+
95
+ def on_charref(code)
96
+ characters([code].pack('U'))
97
+ end
98
+
99
+ def on_charref_hex(code)
100
+ on_charref(code)
101
+ end
102
+
103
+ # def on_start_document; end
104
+
105
+ # def on_end_document; end
106
+
107
+ def on_stag(name)
108
+ @attrs = {}
109
+ end
110
+
111
+ def on_attribute(name)
112
+ @attrs[name] = @curattr = ''
113
+ end
114
+
115
+ def on_attr_value(str)
116
+ @curattr << str
117
+ end
118
+
119
+ def on_attr_entityref(ref)
120
+ @curattr << ENTITY_REF_MAP[ref]
121
+ end
122
+
123
+ def on_attr_charref(code)
124
+ @curattr << [code].pack('U')
125
+ end
126
+
127
+ def on_attr_charref_hex(code)
128
+ on_attr_charref(code)
129
+ end
130
+
131
+ # def on_attribute_end(name); end
132
+
133
+ def on_stag_end_empty(name)
134
+ on_stag_end(name)
135
+ on_etag(name)
136
+ end
137
+
138
+ def on_stag_end(name)
139
+ start_element(name, @attrs)
140
+ end
141
+
142
+ add_factory(self)
143
+ end
144
+
145
+
146
+ end
147
+ end
@@ -0,0 +1 @@
1
+ require 'action_web_service'
@@ -0,0 +1,1379 @@
1
+ #
2
+ # setup.rb
3
+ #
4
+ # Copyright (c) 2000-2004 Minero Aoki
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #
25
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
26
+ # with permission of Minero Aoki.
27
+
28
+ #
29
+
30
+ unless Enumerable.method_defined?(:map) # Ruby 1.4.6
31
+ module Enumerable
32
+ alias map collect
33
+ end
34
+ end
35
+
36
+ unless File.respond_to?(:read) # Ruby 1.6
37
+ def File.read(fname)
38
+ open(fname) {|f|
39
+ return f.read
40
+ }
41
+ end
42
+ end
43
+
44
+ def File.binread(fname)
45
+ open(fname, 'rb') {|f|
46
+ return f.read
47
+ }
48
+ end
49
+
50
+ # for corrupted windows stat(2)
51
+ def File.dir?(path)
52
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
53
+ end
54
+
55
+
56
+ class SetupError < StandardError; end
57
+
58
+ def setup_rb_error(msg)
59
+ raise SetupError, msg
60
+ end
61
+
62
+ #
63
+ # Config
64
+ #
65
+
66
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
67
+ ARGV.delete(arg)
68
+ require arg.split(/=/, 2)[1]
69
+ $".push 'rbconfig.rb'
70
+ else
71
+ require 'rbconfig'
72
+ end
73
+
74
+ def multipackage_install?
75
+ FileTest.directory?(File.dirname($0) + '/packages')
76
+ end
77
+
78
+
79
+ class ConfigItem
80
+ def initialize(name, template, default, desc)
81
+ @name = name.freeze
82
+ @template = template
83
+ @value = default
84
+ @default = default.dup.freeze
85
+ @description = desc
86
+ end
87
+
88
+ attr_reader :name
89
+ attr_reader :description
90
+
91
+ attr_accessor :default
92
+ alias help_default default
93
+
94
+ def help_opt
95
+ "--#{@name}=#{@template}"
96
+ end
97
+
98
+ def value
99
+ @value
100
+ end
101
+
102
+ def eval(table)
103
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
104
+ end
105
+
106
+ def set(val)
107
+ @value = check(val)
108
+ end
109
+
110
+ private
111
+
112
+ def check(val)
113
+ setup_rb_error "config: --#{name} requires argument" unless val
114
+ val
115
+ end
116
+ end
117
+
118
+ class BoolItem < ConfigItem
119
+ def config_type
120
+ 'bool'
121
+ end
122
+
123
+ def help_opt
124
+ "--#{@name}"
125
+ end
126
+
127
+ private
128
+
129
+ def check(val)
130
+ return 'yes' unless val
131
+ unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
132
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
133
+ end
134
+ (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
135
+ end
136
+ end
137
+
138
+ class PathItem < ConfigItem
139
+ def config_type
140
+ 'path'
141
+ end
142
+
143
+ private
144
+
145
+ def check(path)
146
+ setup_rb_error "config: --#{@name} requires argument" unless path
147
+ path[0,1] == '$' ? path : File.expand_path(path)
148
+ end
149
+ end
150
+
151
+ class ProgramItem < ConfigItem
152
+ def config_type
153
+ 'program'
154
+ end
155
+ end
156
+
157
+ class SelectItem < ConfigItem
158
+ def initialize(name, template, default, desc)
159
+ super
160
+ @ok = template.split('/')
161
+ end
162
+
163
+ def config_type
164
+ 'select'
165
+ end
166
+
167
+ private
168
+
169
+ def check(val)
170
+ unless @ok.include?(val.strip)
171
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
172
+ end
173
+ val.strip
174
+ end
175
+ end
176
+
177
+ class PackageSelectionItem < ConfigItem
178
+ def initialize(name, template, default, help_default, desc)
179
+ super name, template, default, desc
180
+ @help_default = help_default
181
+ end
182
+
183
+ attr_reader :help_default
184
+
185
+ def config_type
186
+ 'package'
187
+ end
188
+
189
+ private
190
+
191
+ def check(val)
192
+ unless File.dir?("packages/#{val}")
193
+ setup_rb_error "config: no such package: #{val}"
194
+ end
195
+ val
196
+ end
197
+ end
198
+
199
+ class ConfigTable_class
200
+
201
+ def initialize(items)
202
+ @items = items
203
+ @table = {}
204
+ items.each do |i|
205
+ @table[i.name] = i
206
+ end
207
+ ALIASES.each do |ali, name|
208
+ @table[ali] = @table[name]
209
+ end
210
+ end
211
+
212
+ include Enumerable
213
+
214
+ def each(&block)
215
+ @items.each(&block)
216
+ end
217
+
218
+ def key?(name)
219
+ @table.key?(name)
220
+ end
221
+
222
+ def lookup(name)
223
+ @table[name] or raise ArgumentError, "no such config item: #{name}"
224
+ end
225
+
226
+ def add(item)
227
+ @items.push item
228
+ @table[item.name] = item
229
+ end
230
+
231
+ def remove(name)
232
+ item = lookup(name)
233
+ @items.delete_if {|i| i.name == name }
234
+ @table.delete_if {|name, i| i.name == name }
235
+ item
236
+ end
237
+
238
+ def new
239
+ dup()
240
+ end
241
+
242
+ def savefile
243
+ '.config'
244
+ end
245
+
246
+ def load
247
+ begin
248
+ t = dup()
249
+ File.foreach(savefile()) do |line|
250
+ k, v = *line.split(/=/, 2)
251
+ t[k] = v.strip
252
+ end
253
+ t
254
+ rescue Errno::ENOENT
255
+ setup_rb_error $!.message + "#{File.basename($0)} config first"
256
+ end
257
+ end
258
+
259
+ def save
260
+ @items.each {|i| i.value }
261
+ File.open(savefile(), 'w') {|f|
262
+ @items.each do |i|
263
+ f.printf "%s=%s\n", i.name, i.value if i.value
264
+ end
265
+ }
266
+ end
267
+
268
+ def [](key)
269
+ lookup(key).eval(self)
270
+ end
271
+
272
+ def []=(key, val)
273
+ lookup(key).set val
274
+ end
275
+
276
+ end
277
+
278
+ c = ::Config::CONFIG
279
+
280
+ rubypath = c['bindir'] + '/' + c['ruby_install_name']
281
+
282
+ major = c['MAJOR'].to_i
283
+ minor = c['MINOR'].to_i
284
+ teeny = c['TEENY'].to_i
285
+ version = "#{major}.#{minor}"
286
+
287
+ # ruby ver. >= 1.4.4?
288
+ newpath_p = ((major >= 2) or
289
+ ((major == 1) and
290
+ ((minor >= 5) or
291
+ ((minor == 4) and (teeny >= 4)))))
292
+
293
+ if c['rubylibdir']
294
+ # V < 1.6.3
295
+ _stdruby = c['rubylibdir']
296
+ _siteruby = c['sitedir']
297
+ _siterubyver = c['sitelibdir']
298
+ _siterubyverarch = c['sitearchdir']
299
+ elsif newpath_p
300
+ # 1.4.4 <= V <= 1.6.3
301
+ _stdruby = "$prefix/lib/ruby/#{version}"
302
+ _siteruby = c['sitedir']
303
+ _siterubyver = "$siteruby/#{version}"
304
+ _siterubyverarch = "$siterubyver/#{c['arch']}"
305
+ else
306
+ # V < 1.4.4
307
+ _stdruby = "$prefix/lib/ruby/#{version}"
308
+ _siteruby = "$prefix/lib/ruby/#{version}/site_ruby"
309
+ _siterubyver = _siteruby
310
+ _siterubyverarch = "$siterubyver/#{c['arch']}"
311
+ end
312
+ libdir = '-* dummy libdir *-'
313
+ stdruby = '-* dummy rubylibdir *-'
314
+ siteruby = '-* dummy site_ruby *-'
315
+ siterubyver = '-* dummy site_ruby version *-'
316
+ parameterize = lambda {|path|
317
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
318
+ .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\
319
+ .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\
320
+ .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\
321
+ .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
322
+ }
323
+ libdir = parameterize.call(c['libdir'])
324
+ stdruby = parameterize.call(_stdruby)
325
+ siteruby = parameterize.call(_siteruby)
326
+ siterubyver = parameterize.call(_siterubyver)
327
+ siterubyverarch = parameterize.call(_siterubyverarch)
328
+
329
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
330
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
331
+ else
332
+ makeprog = 'make'
333
+ end
334
+
335
+ common_conf = [
336
+ PathItem.new('prefix', 'path', c['prefix'],
337
+ 'path prefix of target environment'),
338
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
339
+ 'the directory for commands'),
340
+ PathItem.new('libdir', 'path', libdir,
341
+ 'the directory for libraries'),
342
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
343
+ 'the directory for shared data'),
344
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
345
+ 'the directory for man pages'),
346
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
347
+ 'the directory for man pages'),
348
+ PathItem.new('stdruby', 'path', stdruby,
349
+ 'the directory for standard ruby libraries'),
350
+ PathItem.new('siteruby', 'path', siteruby,
351
+ 'the directory for version-independent aux ruby libraries'),
352
+ PathItem.new('siterubyver', 'path', siterubyver,
353
+ 'the directory for aux ruby libraries'),
354
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
355
+ 'the directory for aux ruby binaries'),
356
+ PathItem.new('rbdir', 'path', '$siterubyver',
357
+ 'the directory for ruby scripts'),
358
+ PathItem.new('sodir', 'path', '$siterubyverarch',
359
+ 'the directory for ruby extentions'),
360
+ PathItem.new('rubypath', 'path', rubypath,
361
+ 'the path to set to #! line'),
362
+ ProgramItem.new('rubyprog', 'name', rubypath,
363
+ 'the ruby program using for installation'),
364
+ ProgramItem.new('makeprog', 'name', makeprog,
365
+ 'the make program to compile ruby extentions'),
366
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
367
+ 'shebang line (#!) editing mode'),
368
+ BoolItem.new('without-ext', 'yes/no', 'no',
369
+ 'does not compile/install ruby extentions')
370
+ ]
371
+ class ConfigTable_class # open again
372
+ ALIASES = {
373
+ 'std-ruby' => 'stdruby',
374
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
375
+ 'site-ruby' => 'siterubyver', # For backward compatibility
376
+ 'bin-dir' => 'bindir',
377
+ 'bin-dir' => 'bindir',
378
+ 'rb-dir' => 'rbdir',
379
+ 'so-dir' => 'sodir',
380
+ 'data-dir' => 'datadir',
381
+ 'ruby-path' => 'rubypath',
382
+ 'ruby-prog' => 'rubyprog',
383
+ 'ruby' => 'rubyprog',
384
+ 'make-prog' => 'makeprog',
385
+ 'make' => 'makeprog'
386
+ }
387
+ end
388
+ multipackage_conf = [
389
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
390
+ 'package names that you want to install'),
391
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
392
+ 'package names that you do not want to install')
393
+ ]
394
+ if multipackage_install?
395
+ ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
396
+ else
397
+ ConfigTable = ConfigTable_class.new(common_conf)
398
+ end
399
+
400
+
401
+ module MetaConfigAPI
402
+
403
+ def eval_file_ifexist(fname)
404
+ instance_eval File.read(fname), fname, 1 if File.file?(fname)
405
+ end
406
+
407
+ def config_names
408
+ ConfigTable.map {|i| i.name }
409
+ end
410
+
411
+ def config?(name)
412
+ ConfigTable.key?(name)
413
+ end
414
+
415
+ def bool_config?(name)
416
+ ConfigTable.lookup(name).config_type == 'bool'
417
+ end
418
+
419
+ def path_config?(name)
420
+ ConfigTable.lookup(name).config_type == 'path'
421
+ end
422
+
423
+ def value_config?(name)
424
+ case ConfigTable.lookup(name).config_type
425
+ when 'bool', 'path'
426
+ true
427
+ else
428
+ false
429
+ end
430
+ end
431
+
432
+ def add_config(item)
433
+ ConfigTable.add item
434
+ end
435
+
436
+ def add_bool_config(name, default, desc)
437
+ ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
438
+ end
439
+
440
+ def add_path_config(name, default, desc)
441
+ ConfigTable.add PathItem.new(name, 'path', default, desc)
442
+ end
443
+
444
+ def set_config_default(name, default)
445
+ ConfigTable.lookup(name).default = default
446
+ end
447
+
448
+ def remove_config(name)
449
+ ConfigTable.remove(name)
450
+ end
451
+
452
+ end
453
+
454
+
455
+ #
456
+ # File Operations
457
+ #
458
+
459
+ module FileOperations
460
+
461
+ def mkdir_p(dirname, prefix = nil)
462
+ dirname = prefix + File.expand_path(dirname) if prefix
463
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
464
+ return if no_harm?
465
+
466
+ # does not check '/'... it's too abnormal case
467
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
468
+ if /\A[a-z]:\z/i =~ dirs[0]
469
+ disk = dirs.shift
470
+ dirs[0] = disk + dirs[0]
471
+ end
472
+ dirs.each_index do |idx|
473
+ path = dirs[0..idx].join('')
474
+ Dir.mkdir path unless File.dir?(path)
475
+ end
476
+ end
477
+
478
+ def rm_f(fname)
479
+ $stderr.puts "rm -f #{fname}" if verbose?
480
+ return if no_harm?
481
+
482
+ if File.exist?(fname) or File.symlink?(fname)
483
+ File.chmod 0777, fname
484
+ File.unlink fname
485
+ end
486
+ end
487
+
488
+ def rm_rf(dn)
489
+ $stderr.puts "rm -rf #{dn}" if verbose?
490
+ return if no_harm?
491
+
492
+ Dir.chdir dn
493
+ Dir.foreach('.') do |fn|
494
+ next if fn == '.'
495
+ next if fn == '..'
496
+ if File.dir?(fn)
497
+ verbose_off {
498
+ rm_rf fn
499
+ }
500
+ else
501
+ verbose_off {
502
+ rm_f fn
503
+ }
504
+ end
505
+ end
506
+ Dir.chdir '..'
507
+ Dir.rmdir dn
508
+ end
509
+
510
+ def move_file(src, dest)
511
+ File.unlink dest if File.exist?(dest)
512
+ begin
513
+ File.rename src, dest
514
+ rescue
515
+ File.open(dest, 'wb') {|f| f.write File.binread(src) }
516
+ File.chmod File.stat(src).mode, dest
517
+ File.unlink src
518
+ end
519
+ end
520
+
521
+ def install(from, dest, mode, prefix = nil)
522
+ $stderr.puts "install #{from} #{dest}" if verbose?
523
+ return if no_harm?
524
+
525
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
526
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
527
+ str = File.binread(from)
528
+ if diff?(str, realdest)
529
+ verbose_off {
530
+ rm_f realdest if File.exist?(realdest)
531
+ }
532
+ File.open(realdest, 'wb') {|f|
533
+ f.write str
534
+ }
535
+ File.chmod mode, realdest
536
+
537
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
538
+ if prefix
539
+ f.puts realdest.sub(prefix, '')
540
+ else
541
+ f.puts realdest
542
+ end
543
+ }
544
+ end
545
+ end
546
+
547
+ def diff?(new_content, path)
548
+ return true unless File.exist?(path)
549
+ new_content != File.binread(path)
550
+ end
551
+
552
+ def command(str)
553
+ $stderr.puts str if verbose?
554
+ system str or raise RuntimeError, "'system #{str}' failed"
555
+ end
556
+
557
+ def ruby(str)
558
+ command config('rubyprog') + ' ' + str
559
+ end
560
+
561
+ def make(task = '')
562
+ command config('makeprog') + ' ' + task
563
+ end
564
+
565
+ def extdir?(dir)
566
+ File.exist?(dir + '/MANIFEST')
567
+ end
568
+
569
+ def all_files_in(dirname)
570
+ Dir.open(dirname) {|d|
571
+ return d.select {|ent| File.file?("#{dirname}/#{ent}") }
572
+ }
573
+ end
574
+
575
+ REJECT_DIRS = %w(
576
+ CVS SCCS RCS CVS.adm .svn
577
+ )
578
+
579
+ def all_dirs_in(dirname)
580
+ Dir.open(dirname) {|d|
581
+ return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
582
+ }
583
+ end
584
+
585
+ end
586
+
587
+
588
+ #
589
+ # Main Installer
590
+ #
591
+
592
+ module HookUtils
593
+
594
+ def run_hook(name)
595
+ try_run_hook "#{curr_srcdir()}/#{name}" or
596
+ try_run_hook "#{curr_srcdir()}/#{name}.rb"
597
+ end
598
+
599
+ def try_run_hook(fname)
600
+ return false unless File.file?(fname)
601
+ begin
602
+ instance_eval File.read(fname), fname, 1
603
+ rescue
604
+ setup_rb_error "hook #{fname} failed:\n" + $!.message
605
+ end
606
+ true
607
+ end
608
+
609
+ end
610
+
611
+
612
+ module HookScriptAPI
613
+
614
+ def get_config(key)
615
+ @config[key]
616
+ end
617
+
618
+ alias config get_config
619
+
620
+ def set_config(key, val)
621
+ @config[key] = val
622
+ end
623
+
624
+ #
625
+ # srcdir/objdir (works only in the package directory)
626
+ #
627
+
628
+ #abstract srcdir_root
629
+ #abstract objdir_root
630
+ #abstract relpath
631
+
632
+ def curr_srcdir
633
+ "#{srcdir_root()}/#{relpath()}"
634
+ end
635
+
636
+ def curr_objdir
637
+ "#{objdir_root()}/#{relpath()}"
638
+ end
639
+
640
+ def srcfile(path)
641
+ "#{curr_srcdir()}/#{path}"
642
+ end
643
+
644
+ def srcexist?(path)
645
+ File.exist?(srcfile(path))
646
+ end
647
+
648
+ def srcdirectory?(path)
649
+ File.dir?(srcfile(path))
650
+ end
651
+
652
+ def srcfile?(path)
653
+ File.file? srcfile(path)
654
+ end
655
+
656
+ def srcentries(path = '.')
657
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
658
+ return d.to_a - %w(. ..)
659
+ }
660
+ end
661
+
662
+ def srcfiles(path = '.')
663
+ srcentries(path).select {|fname|
664
+ File.file?(File.join(curr_srcdir(), path, fname))
665
+ }
666
+ end
667
+
668
+ def srcdirectories(path = '.')
669
+ srcentries(path).select {|fname|
670
+ File.dir?(File.join(curr_srcdir(), path, fname))
671
+ }
672
+ end
673
+
674
+ end
675
+
676
+
677
+ class ToplevelInstaller
678
+
679
+ Version = '3.3.1'
680
+ Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
681
+
682
+ TASKS = [
683
+ [ 'all', 'do config, setup, then install' ],
684
+ [ 'config', 'saves your configurations' ],
685
+ [ 'show', 'shows current configuration' ],
686
+ [ 'setup', 'compiles ruby extentions and others' ],
687
+ [ 'install', 'installs files' ],
688
+ [ 'clean', "does `make clean' for each extention" ],
689
+ [ 'distclean',"does `make distclean' for each extention" ]
690
+ ]
691
+
692
+ def ToplevelInstaller.invoke
693
+ instance().invoke
694
+ end
695
+
696
+ @singleton = nil
697
+
698
+ def ToplevelInstaller.instance
699
+ @singleton ||= new(File.dirname($0))
700
+ @singleton
701
+ end
702
+
703
+ include MetaConfigAPI
704
+
705
+ def initialize(ardir_root)
706
+ @config = nil
707
+ @options = { 'verbose' => true }
708
+ @ardir = File.expand_path(ardir_root)
709
+ end
710
+
711
+ def inspect
712
+ "#<#{self.class} #{__id__()}>"
713
+ end
714
+
715
+ def invoke
716
+ run_metaconfigs
717
+ case task = parsearg_global()
718
+ when nil, 'all'
719
+ @config = load_config('config')
720
+ parsearg_config
721
+ init_installers
722
+ exec_config
723
+ exec_setup
724
+ exec_install
725
+ else
726
+ @config = load_config(task)
727
+ __send__ "parsearg_#{task}"
728
+ init_installers
729
+ __send__ "exec_#{task}"
730
+ end
731
+ end
732
+
733
+ def run_metaconfigs
734
+ eval_file_ifexist "#{@ardir}/metaconfig"
735
+ end
736
+
737
+ def load_config(task)
738
+ case task
739
+ when 'config'
740
+ ConfigTable.new
741
+ when 'clean', 'distclean'
742
+ if File.exist?(ConfigTable.savefile)
743
+ then ConfigTable.load
744
+ else ConfigTable.new
745
+ end
746
+ else
747
+ ConfigTable.load
748
+ end
749
+ end
750
+
751
+ def init_installers
752
+ @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
753
+ end
754
+
755
+ #
756
+ # Hook Script API bases
757
+ #
758
+
759
+ def srcdir_root
760
+ @ardir
761
+ end
762
+
763
+ def objdir_root
764
+ '.'
765
+ end
766
+
767
+ def relpath
768
+ '.'
769
+ end
770
+
771
+ #
772
+ # Option Parsing
773
+ #
774
+
775
+ def parsearg_global
776
+ valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
777
+
778
+ while arg = ARGV.shift
779
+ case arg
780
+ when /\A\w+\z/
781
+ setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
782
+ return arg
783
+
784
+ when '-q', '--quiet'
785
+ @options['verbose'] = false
786
+
787
+ when '--verbose'
788
+ @options['verbose'] = true
789
+
790
+ when '-h', '--help'
791
+ print_usage $stdout
792
+ exit 0
793
+
794
+ when '-v', '--version'
795
+ puts "#{File.basename($0)} version #{Version}"
796
+ exit 0
797
+
798
+ when '--copyright'
799
+ puts Copyright
800
+ exit 0
801
+
802
+ else
803
+ setup_rb_error "unknown global option '#{arg}'"
804
+ end
805
+ end
806
+
807
+ nil
808
+ end
809
+
810
+
811
+ def parsearg_no_options
812
+ unless ARGV.empty?
813
+ setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}"
814
+ end
815
+ end
816
+
817
+ alias parsearg_show parsearg_no_options
818
+ alias parsearg_setup parsearg_no_options
819
+ alias parsearg_clean parsearg_no_options
820
+ alias parsearg_distclean parsearg_no_options
821
+
822
+ def parsearg_config
823
+ re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
824
+ @options['config-opt'] = []
825
+
826
+ while i = ARGV.shift
827
+ if /\A--?\z/ =~ i
828
+ @options['config-opt'] = ARGV.dup
829
+ break
830
+ end
831
+ m = re.match(i) or setup_rb_error "config: unknown option #{i}"
832
+ name, value = *m.to_a[1,2]
833
+ @config[name] = value
834
+ end
835
+ end
836
+
837
+ def parsearg_install
838
+ @options['no-harm'] = false
839
+ @options['install-prefix'] = ''
840
+ while a = ARGV.shift
841
+ case a
842
+ when /\A--no-harm\z/
843
+ @options['no-harm'] = true
844
+ when /\A--prefix=(.*)\z/
845
+ path = $1
846
+ path = File.expand_path(path) unless path[0,1] == '/'
847
+ @options['install-prefix'] = path
848
+ else
849
+ setup_rb_error "install: unknown option #{a}"
850
+ end
851
+ end
852
+ end
853
+
854
+ def print_usage(out)
855
+ out.puts 'Typical Installation Procedure:'
856
+ out.puts " $ ruby #{File.basename $0} config"
857
+ out.puts " $ ruby #{File.basename $0} setup"
858
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
859
+ out.puts
860
+ out.puts 'Detailed Usage:'
861
+ out.puts " ruby #{File.basename $0} <global option>"
862
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
863
+
864
+ fmt = " %-24s %s\n"
865
+ out.puts
866
+ out.puts 'Global options:'
867
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
868
+ out.printf fmt, ' --verbose', 'output messages verbosely'
869
+ out.printf fmt, '-h,--help', 'print this message'
870
+ out.printf fmt, '-v,--version', 'print version and quit'
871
+ out.printf fmt, ' --copyright', 'print copyright and quit'
872
+ out.puts
873
+ out.puts 'Tasks:'
874
+ TASKS.each do |name, desc|
875
+ out.printf fmt, name, desc
876
+ end
877
+
878
+ fmt = " %-24s %s [%s]\n"
879
+ out.puts
880
+ out.puts 'Options for CONFIG or ALL:'
881
+ ConfigTable.each do |item|
882
+ out.printf fmt, item.help_opt, item.description, item.help_default
883
+ end
884
+ out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
885
+ out.puts
886
+ out.puts 'Options for INSTALL:'
887
+ out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
888
+ out.printf fmt, '--prefix=path', 'install path prefix', '$prefix'
889
+ out.puts
890
+ end
891
+
892
+ #
893
+ # Task Handlers
894
+ #
895
+
896
+ def exec_config
897
+ @installer.exec_config
898
+ @config.save # must be final
899
+ end
900
+
901
+ def exec_setup
902
+ @installer.exec_setup
903
+ end
904
+
905
+ def exec_install
906
+ @installer.exec_install
907
+ end
908
+
909
+ def exec_show
910
+ ConfigTable.each do |i|
911
+ printf "%-20s %s\n", i.name, i.value
912
+ end
913
+ end
914
+
915
+ def exec_clean
916
+ @installer.exec_clean
917
+ end
918
+
919
+ def exec_distclean
920
+ @installer.exec_distclean
921
+ end
922
+
923
+ end
924
+
925
+
926
+ class ToplevelInstallerMulti < ToplevelInstaller
927
+
928
+ include HookUtils
929
+ include HookScriptAPI
930
+ include FileOperations
931
+
932
+ def initialize(ardir)
933
+ super
934
+ @packages = all_dirs_in("#{@ardir}/packages")
935
+ raise 'no package exists' if @packages.empty?
936
+ end
937
+
938
+ def run_metaconfigs
939
+ eval_file_ifexist "#{@ardir}/metaconfig"
940
+ @packages.each do |name|
941
+ eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
942
+ end
943
+ end
944
+
945
+ def init_installers
946
+ @installers = {}
947
+ @packages.each do |pack|
948
+ @installers[pack] = Installer.new(@config, @options,
949
+ "#{@ardir}/packages/#{pack}",
950
+ "packages/#{pack}")
951
+ end
952
+
953
+ with = extract_selection(config('with'))
954
+ without = extract_selection(config('without'))
955
+ @selected = @installers.keys.select {|name|
956
+ (with.empty? or with.include?(name)) \
957
+ and not without.include?(name)
958
+ }
959
+ end
960
+
961
+ def extract_selection(list)
962
+ a = list.split(/,/)
963
+ a.each do |name|
964
+ setup_rb_error "no such package: #{name}" unless @installers.key?(name)
965
+ end
966
+ a
967
+ end
968
+
969
+ def print_usage(f)
970
+ super
971
+ f.puts 'Included packages:'
972
+ f.puts ' ' + @packages.sort.join(' ')
973
+ f.puts
974
+ end
975
+
976
+ #
977
+ # multi-package metaconfig API
978
+ #
979
+
980
+ attr_reader :packages
981
+
982
+ def declare_packages(list)
983
+ raise 'package list is empty' if list.empty?
984
+ list.each do |name|
985
+ raise "directory packages/#{name} does not exist"\
986
+ unless File.dir?("#{@ardir}/packages/#{name}")
987
+ end
988
+ @packages = list
989
+ end
990
+
991
+ #
992
+ # Task Handlers
993
+ #
994
+
995
+ def exec_config
996
+ run_hook 'pre-config'
997
+ each_selected_installers {|inst| inst.exec_config }
998
+ run_hook 'post-config'
999
+ @config.save # must be final
1000
+ end
1001
+
1002
+ def exec_setup
1003
+ run_hook 'pre-setup'
1004
+ each_selected_installers {|inst| inst.exec_setup }
1005
+ run_hook 'post-setup'
1006
+ end
1007
+
1008
+ def exec_install
1009
+ run_hook 'pre-install'
1010
+ each_selected_installers {|inst| inst.exec_install }
1011
+ run_hook 'post-install'
1012
+ end
1013
+
1014
+ def exec_clean
1015
+ rm_f ConfigTable.savefile
1016
+ run_hook 'pre-clean'
1017
+ each_selected_installers {|inst| inst.exec_clean }
1018
+ run_hook 'post-clean'
1019
+ end
1020
+
1021
+ def exec_distclean
1022
+ rm_f ConfigTable.savefile
1023
+ run_hook 'pre-distclean'
1024
+ each_selected_installers {|inst| inst.exec_distclean }
1025
+ run_hook 'post-distclean'
1026
+ end
1027
+
1028
+ #
1029
+ # lib
1030
+ #
1031
+
1032
+ def each_selected_installers
1033
+ Dir.mkdir 'packages' unless File.dir?('packages')
1034
+ @selected.each do |pack|
1035
+ $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
1036
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
1037
+ Dir.chdir "packages/#{pack}"
1038
+ yield @installers[pack]
1039
+ Dir.chdir '../..'
1040
+ end
1041
+ end
1042
+
1043
+ def verbose?
1044
+ @options['verbose']
1045
+ end
1046
+
1047
+ def no_harm?
1048
+ @options['no-harm']
1049
+ end
1050
+
1051
+ end
1052
+
1053
+
1054
+ class Installer
1055
+
1056
+ FILETYPES = %w( bin lib ext data )
1057
+
1058
+ include HookScriptAPI
1059
+ include HookUtils
1060
+ include FileOperations
1061
+
1062
+ def initialize(config, opt, srcroot, objroot)
1063
+ @config = config
1064
+ @options = opt
1065
+ @srcdir = File.expand_path(srcroot)
1066
+ @objdir = File.expand_path(objroot)
1067
+ @currdir = '.'
1068
+ end
1069
+
1070
+ def inspect
1071
+ "#<#{self.class} #{File.basename(@srcdir)}>"
1072
+ end
1073
+
1074
+ #
1075
+ # Hook Script API base methods
1076
+ #
1077
+
1078
+ def srcdir_root
1079
+ @srcdir
1080
+ end
1081
+
1082
+ def objdir_root
1083
+ @objdir
1084
+ end
1085
+
1086
+ def relpath
1087
+ @currdir
1088
+ end
1089
+
1090
+ #
1091
+ # configs/options
1092
+ #
1093
+
1094
+ def no_harm?
1095
+ @options['no-harm']
1096
+ end
1097
+
1098
+ def verbose?
1099
+ @options['verbose']
1100
+ end
1101
+
1102
+ def verbose_off
1103
+ begin
1104
+ save, @options['verbose'] = @options['verbose'], false
1105
+ yield
1106
+ ensure
1107
+ @options['verbose'] = save
1108
+ end
1109
+ end
1110
+
1111
+ #
1112
+ # TASK config
1113
+ #
1114
+
1115
+ def exec_config
1116
+ exec_task_traverse 'config'
1117
+ end
1118
+
1119
+ def config_dir_bin(rel)
1120
+ end
1121
+
1122
+ def config_dir_lib(rel)
1123
+ end
1124
+
1125
+ def config_dir_ext(rel)
1126
+ extconf if extdir?(curr_srcdir())
1127
+ end
1128
+
1129
+ def extconf
1130
+ opt = @options['config-opt'].join(' ')
1131
+ command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
1132
+ end
1133
+
1134
+ def config_dir_data(rel)
1135
+ end
1136
+
1137
+ #
1138
+ # TASK setup
1139
+ #
1140
+
1141
+ def exec_setup
1142
+ exec_task_traverse 'setup'
1143
+ end
1144
+
1145
+ def setup_dir_bin(rel)
1146
+ all_files_in(curr_srcdir()).each do |fname|
1147
+ adjust_shebang "#{curr_srcdir()}/#{fname}"
1148
+ end
1149
+ end
1150
+
1151
+ def adjust_shebang(path)
1152
+ return if no_harm?
1153
+ tmpfile = File.basename(path) + '.tmp'
1154
+ begin
1155
+ File.open(path, 'rb') {|r|
1156
+ first = r.gets
1157
+ return unless File.basename(config('rubypath')) == 'ruby'
1158
+ return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
1159
+ $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
1160
+ File.open(tmpfile, 'wb') {|w|
1161
+ w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
1162
+ w.write r.read
1163
+ }
1164
+ move_file tmpfile, File.basename(path)
1165
+ }
1166
+ ensure
1167
+ File.unlink tmpfile if File.exist?(tmpfile)
1168
+ end
1169
+ end
1170
+
1171
+ def setup_dir_lib(rel)
1172
+ end
1173
+
1174
+ def setup_dir_ext(rel)
1175
+ make if extdir?(curr_srcdir())
1176
+ end
1177
+
1178
+ def setup_dir_data(rel)
1179
+ end
1180
+
1181
+ #
1182
+ # TASK install
1183
+ #
1184
+
1185
+ def exec_install
1186
+ rm_f 'InstalledFiles'
1187
+ exec_task_traverse 'install'
1188
+ end
1189
+
1190
+ def install_dir_bin(rel)
1191
+ install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
1192
+ end
1193
+
1194
+ def install_dir_lib(rel)
1195
+ install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
1196
+ end
1197
+
1198
+ def install_dir_ext(rel)
1199
+ return unless extdir?(curr_srcdir())
1200
+ install_files ruby_extentions('.'),
1201
+ "#{config('sodir')}/#{File.dirname(rel)}",
1202
+ 0555
1203
+ end
1204
+
1205
+ def install_dir_data(rel)
1206
+ install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
1207
+ end
1208
+
1209
+ def install_files(list, dest, mode)
1210
+ mkdir_p dest, @options['install-prefix']
1211
+ list.each do |fname|
1212
+ install fname, dest, mode, @options['install-prefix']
1213
+ end
1214
+ end
1215
+
1216
+ def ruby_scripts
1217
+ collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
1218
+ end
1219
+
1220
+ # picked up many entries from cvs-1.11.1/src/ignore.c
1221
+ reject_patterns = %w(
1222
+ core RCSLOG tags TAGS .make.state
1223
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1224
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
1225
+
1226
+ *.org *.in .*
1227
+ )
1228
+ mapping = {
1229
+ '.' => '\.',
1230
+ '$' => '\$',
1231
+ '#' => '\#',
1232
+ '*' => '.*'
1233
+ }
1234
+ REJECT_PATTERNS = Regexp.new('\A(?:' +
1235
+ reject_patterns.map {|pat|
1236
+ pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
1237
+ }.join('|') +
1238
+ ')\z')
1239
+
1240
+ def collect_filenames_auto
1241
+ mapdir((existfiles() - hookfiles()).reject {|fname|
1242
+ REJECT_PATTERNS =~ fname
1243
+ })
1244
+ end
1245
+
1246
+ def existfiles
1247
+ all_files_in(curr_srcdir()) | all_files_in('.')
1248
+ end
1249
+
1250
+ def hookfiles
1251
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
1252
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
1253
+ }.flatten
1254
+ end
1255
+
1256
+ def mapdir(filelist)
1257
+ filelist.map {|fname|
1258
+ if File.exist?(fname) # objdir
1259
+ fname
1260
+ else # srcdir
1261
+ File.join(curr_srcdir(), fname)
1262
+ end
1263
+ }
1264
+ end
1265
+
1266
+ def ruby_extentions(dir)
1267
+ Dir.open(dir) {|d|
1268
+ ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
1269
+ if ents.empty?
1270
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
1271
+ end
1272
+ return ents
1273
+ }
1274
+ end
1275
+
1276
+ #
1277
+ # TASK clean
1278
+ #
1279
+
1280
+ def exec_clean
1281
+ exec_task_traverse 'clean'
1282
+ rm_f ConfigTable.savefile
1283
+ rm_f 'InstalledFiles'
1284
+ end
1285
+
1286
+ def clean_dir_bin(rel)
1287
+ end
1288
+
1289
+ def clean_dir_lib(rel)
1290
+ end
1291
+
1292
+ def clean_dir_ext(rel)
1293
+ return unless extdir?(curr_srcdir())
1294
+ make 'clean' if File.file?('Makefile')
1295
+ end
1296
+
1297
+ def clean_dir_data(rel)
1298
+ end
1299
+
1300
+ #
1301
+ # TASK distclean
1302
+ #
1303
+
1304
+ def exec_distclean
1305
+ exec_task_traverse 'distclean'
1306
+ rm_f ConfigTable.savefile
1307
+ rm_f 'InstalledFiles'
1308
+ end
1309
+
1310
+ def distclean_dir_bin(rel)
1311
+ end
1312
+
1313
+ def distclean_dir_lib(rel)
1314
+ end
1315
+
1316
+ def distclean_dir_ext(rel)
1317
+ return unless extdir?(curr_srcdir())
1318
+ make 'distclean' if File.file?('Makefile')
1319
+ end
1320
+
1321
+ #
1322
+ # lib
1323
+ #
1324
+
1325
+ def exec_task_traverse(task)
1326
+ run_hook "pre-#{task}"
1327
+ FILETYPES.each do |type|
1328
+ if config('without-ext') == 'yes' and type == 'ext'
1329
+ $stderr.puts 'skipping ext/* by user option' if verbose?
1330
+ next
1331
+ end
1332
+ traverse task, type, "#{task}_dir_#{type}"
1333
+ end
1334
+ run_hook "post-#{task}"
1335
+ end
1336
+
1337
+ def traverse(task, rel, mid)
1338
+ dive_into(rel) {
1339
+ run_hook "pre-#{task}"
1340
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
1341
+ all_dirs_in(curr_srcdir()).each do |d|
1342
+ traverse task, "#{rel}/#{d}", mid
1343
+ end
1344
+ run_hook "post-#{task}"
1345
+ }
1346
+ end
1347
+
1348
+ def dive_into(rel)
1349
+ return unless File.dir?("#{@srcdir}/#{rel}")
1350
+
1351
+ dir = File.basename(rel)
1352
+ Dir.mkdir dir unless File.dir?(dir)
1353
+ prevdir = Dir.pwd
1354
+ Dir.chdir dir
1355
+ $stderr.puts '---> ' + rel if verbose?
1356
+ @currdir = rel
1357
+ yield
1358
+ Dir.chdir prevdir
1359
+ $stderr.puts '<--- ' + rel if verbose?
1360
+ @currdir = File.dirname(rel)
1361
+ end
1362
+
1363
+ end
1364
+
1365
+
1366
+ if $0 == __FILE__
1367
+ begin
1368
+ if multipackage_install?
1369
+ ToplevelInstallerMulti.invoke
1370
+ else
1371
+ ToplevelInstaller.invoke
1372
+ end
1373
+ rescue SetupError
1374
+ raise if $DEBUG
1375
+ $stderr.puts $!.message
1376
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
1377
+ exit 1
1378
+ end
1379
+ end