shopify-cli 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +9 -0
  5. data/README.md +39 -7
  6. data/Rakefile +2 -0
  7. data/dev.yml +2 -2
  8. data/docs/_config.yml +1 -18
  9. data/docs/app/node/commands/index.md +2 -80
  10. data/docs/app/node/index.md +2 -33
  11. data/docs/app/rails/commands/index.md +2 -78
  12. data/docs/app/rails/index.md +2 -34
  13. data/docs/core/index.md +2 -84
  14. data/docs/getting-started/index.md +2 -25
  15. data/docs/getting-started/install/index.md +1 -118
  16. data/docs/getting-started/migrate/index.md +2 -94
  17. data/docs/getting-started/uninstall/index.md +2 -35
  18. data/docs/getting-started/upgrade/index.md +2 -39
  19. data/docs/help/start-app/index.md +2 -4
  20. data/docs/index.md +2 -24
  21. data/install.sh +1 -1
  22. data/lib/project_types/extension/cli.rb +19 -10
  23. data/lib/project_types/extension/commands/extension_command.rb +2 -2
  24. data/lib/project_types/extension/features/argo.rb +117 -0
  25. data/lib/project_types/extension/forms/create.rb +2 -2
  26. data/lib/project_types/extension/models/specification.rb +35 -0
  27. data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +19 -0
  28. data/lib/project_types/extension/models/specification_handlers/default.rb +67 -0
  29. data/lib/project_types/extension/models/specifications.rb +77 -0
  30. data/lib/project_types/extension/tasks/configure_features.rb +52 -0
  31. data/lib/project_types/extension/tasks/fetch_specifications.rb +38 -0
  32. data/lib/project_types/node/commands/create.rb +3 -1
  33. data/lib/project_types/node/commands/generate.rb +2 -11
  34. data/lib/project_types/node/messages/messages.rb +9 -44
  35. data/lib/project_types/rails/commands/create.rb +8 -9
  36. data/lib/project_types/rails/forms/create.rb +1 -1
  37. data/lib/project_types/rails/gem.rb +1 -1
  38. data/lib/project_types/rails/messages/messages.rb +1 -1
  39. data/lib/project_types/script/cli.rb +7 -4
  40. data/lib/project_types/script/commands/create.rb +6 -4
  41. data/lib/project_types/script/commands/push.rb +5 -13
  42. data/lib/project_types/script/config/extension_points.yml +9 -5
  43. data/lib/project_types/script/errors.rb +17 -0
  44. data/lib/project_types/script/forms/create.rb +26 -2
  45. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +10 -1
  46. data/lib/project_types/script/layers/application/build_script.rb +9 -4
  47. data/lib/project_types/script/layers/application/create_script.rb +12 -10
  48. data/lib/project_types/script/layers/application/extension_points.rb +24 -0
  49. data/lib/project_types/script/layers/application/push_script.rb +18 -16
  50. data/lib/project_types/script/layers/domain/errors.rb +4 -0
  51. data/lib/project_types/script/layers/domain/extension_point.rb +62 -6
  52. data/lib/project_types/script/layers/domain/metadata.rb +55 -0
  53. data/lib/project_types/script/layers/domain/push_package.rb +25 -6
  54. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +6 -6
  55. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +16 -6
  56. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +10 -4
  57. data/lib/project_types/script/layers/infrastructure/project_creator.rb +2 -1
  58. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +25 -13
  59. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +72 -0
  60. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +59 -0
  61. data/lib/project_types/script/layers/infrastructure/script_service.rb +7 -1
  62. data/lib/project_types/script/layers/infrastructure/task_runner.rb +4 -3
  63. data/lib/project_types/script/messages/messages.rb +39 -8
  64. data/lib/project_types/script/script_project.rb +25 -16
  65. data/lib/project_types/script/ui/error_handler.rb +34 -1
  66. data/lib/project_types/theme/cli.rb +40 -0
  67. data/lib/project_types/theme/commands/connect.rb +54 -0
  68. data/lib/project_types/theme/commands/create.rb +48 -0
  69. data/lib/project_types/theme/commands/deploy.rb +38 -0
  70. data/lib/project_types/theme/commands/generate.rb +20 -0
  71. data/lib/project_types/theme/commands/generate/env.rb +79 -0
  72. data/lib/project_types/theme/commands/push.rb +55 -0
  73. data/lib/project_types/theme/commands/serve.rb +31 -0
  74. data/lib/project_types/theme/forms/connect.rb +34 -0
  75. data/lib/project_types/theme/forms/create.rb +22 -0
  76. data/lib/project_types/theme/messages/messages.rb +147 -0
  77. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +78 -0
  78. data/lib/project_types/theme/themekit.rb +113 -0
  79. data/lib/shopify-cli/admin_api.rb +42 -2
  80. data/lib/shopify-cli/api.rb +27 -24
  81. data/lib/shopify-cli/commands/system.rb +1 -1
  82. data/lib/shopify-cli/context.rb +23 -2
  83. data/lib/shopify-cli/feature.rb +0 -2
  84. data/lib/shopify-cli/http_request.rb +20 -8
  85. data/lib/shopify-cli/messages/messages.rb +6 -3
  86. data/lib/shopify-cli/method_object.rb +104 -0
  87. data/lib/shopify-cli/partners_api.rb +8 -2
  88. data/lib/shopify-cli/project_type.rb +1 -1
  89. data/lib/shopify-cli/resolve_constant.rb +25 -0
  90. data/lib/shopify-cli/result.rb +432 -0
  91. data/lib/shopify-cli/shopifolk.rb +3 -2
  92. data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -5
  93. data/lib/shopify-cli/tunnel.rb +7 -1
  94. data/lib/shopify-cli/version.rb +1 -1
  95. data/lib/shopify_cli.rb +4 -1
  96. data/shopify.fish +1 -1
  97. data/shopify.sh +1 -1
  98. data/vendor/deps/cli-kit/REVISION +1 -1
  99. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +2 -2
  100. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +3 -3
  101. data/vendor/deps/cli-ui/REVISION +1 -1
  102. data/vendor/deps/cli-ui/lib/cli/ui.rb +26 -22
  103. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +4 -6
  104. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -3
  105. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +8 -9
  106. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -1
  107. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +1 -0
  108. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +15 -3
  109. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +4 -11
  110. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -5
  111. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +10 -10
  112. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +1 -1
  113. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +56 -0
  114. data/vendor/deps/webrick/.gitignore +9 -0
  115. data/vendor/deps/webrick/Gemfile +3 -0
  116. data/vendor/deps/webrick/LICENSE.txt +22 -0
  117. data/vendor/deps/webrick/README.md +61 -0
  118. data/vendor/deps/webrick/Rakefile +10 -0
  119. data/vendor/deps/webrick/lib/webrick.rb +232 -0
  120. data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
  121. data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
  122. data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
  123. data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
  124. data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
  125. data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
  126. data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
  127. data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
  128. data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
  129. data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
  130. data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
  131. data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
  132. data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
  133. data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
  134. data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
  135. data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
  136. data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
  137. data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
  138. data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
  139. data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
  140. data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
  141. data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  142. data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
  143. data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
  144. data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
  145. data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
  146. data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
  147. data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
  148. data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
  149. data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
  150. data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
  151. data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
  152. data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
  153. data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
  154. data/vendor/deps/webrick/webrick.gemspec +74 -0
  155. metadata +70 -26
  156. data/docs/Gemfile +0 -5
  157. data/docs/Gemfile.lock +0 -258
  158. data/docs/_data/nav.yml +0 -35
  159. data/docs/_includes/footer.html +0 -15
  160. data/docs/_includes/head.html +0 -19
  161. data/docs/_includes/sidebar_nav.html +0 -22
  162. data/docs/_includes/toc.html +0 -112
  163. data/docs/_layouts/default.html +0 -79
  164. data/docs/css/docs.css +0 -157
  165. data/docs/images/header.png +0 -0
  166. data/docs/installing-ruby.md +0 -28
  167. data/lib/project_types/extension/features/argo/admin.rb +0 -20
  168. data/lib/project_types/extension/features/argo/base.rb +0 -129
  169. data/lib/project_types/extension/features/argo/checkout.rb +0 -20
  170. data/lib/project_types/extension/models/type.rb +0 -81
  171. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +0 -23
  172. data/lib/project_types/extension/models/types/product_subscription.rb +0 -24
  173. data/lib/project_types/node/commands/generate/billing.rb +0 -39
  174. data/lib/project_types/node/commands/generate/page.rb +0 -59
  175. data/lib/project_types/node/commands/generate/webhook.rb +0 -37
  176. data/lib/project_types/script/layers/domain/script.rb +0 -18
  177. data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -47
  178. data/lib/project_types/script/templates/ts/as-pect.config.js +0 -27
  179. data/lib/project_types/script/templates/ts/as-pect.d.ts +0 -1
@@ -0,0 +1,215 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ssl.rb -- SSL/TLS enhancement for GenericServer
4
+ #
5
+ # Copyright (c) 2003 GOTOU Yuuzou All rights reserved.
6
+ #
7
+ # $Id$
8
+
9
+ require 'webrick'
10
+ require 'openssl'
11
+
12
+ module WEBrick
13
+ module Config
14
+ svrsoft = General[:ServerSoftware]
15
+ osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
16
+
17
+ ##
18
+ # Default SSL server configuration.
19
+ #
20
+ # WEBrick can automatically create a self-signed certificate if
21
+ # <code>:SSLCertName</code> is set. For more information on the various
22
+ # SSL options see OpenSSL::SSL::SSLContext.
23
+ #
24
+ # :ServerSoftware ::
25
+ # The server software name used in the Server: header.
26
+ # :SSLEnable :: false,
27
+ # Enable SSL for this server. Defaults to false.
28
+ # :SSLCertificate ::
29
+ # The SSL certificate for the server.
30
+ # :SSLPrivateKey ::
31
+ # The SSL private key for the server certificate.
32
+ # :SSLClientCA :: nil,
33
+ # Array of certificates that will be sent to the client.
34
+ # :SSLExtraChainCert :: nil,
35
+ # Array of certificates that will be added to the certificate chain
36
+ # :SSLCACertificateFile :: nil,
37
+ # Path to a CA certificate file
38
+ # :SSLCACertificatePath :: nil,
39
+ # Path to a directory containing CA certificates
40
+ # :SSLCertificateStore :: nil,
41
+ # OpenSSL::X509::Store used for certificate validation of the client
42
+ # :SSLTmpDhCallback :: nil,
43
+ # Callback invoked when DH parameters are required.
44
+ # :SSLVerifyClient ::
45
+ # Sets whether the client is verified. This defaults to VERIFY_NONE
46
+ # which is typical for an HTTPS server.
47
+ # :SSLVerifyDepth ::
48
+ # Number of CA certificates to walk when verifying a certificate chain
49
+ # :SSLVerifyCallback ::
50
+ # Custom certificate verification callback
51
+ # :SSLServerNameCallback::
52
+ # Custom servername indication callback
53
+ # :SSLTimeout ::
54
+ # Maximum session lifetime
55
+ # :SSLOptions ::
56
+ # Various SSL options
57
+ # :SSLCiphers ::
58
+ # Ciphers to be used
59
+ # :SSLStartImmediately ::
60
+ # Immediately start SSL upon connection? Defaults to true
61
+ # :SSLCertName ::
62
+ # SSL certificate name. Must be set to enable automatic certificate
63
+ # creation.
64
+ # :SSLCertComment ::
65
+ # Comment used during automatic certificate creation.
66
+
67
+ SSL = {
68
+ :ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}",
69
+ :SSLEnable => false,
70
+ :SSLCertificate => nil,
71
+ :SSLPrivateKey => nil,
72
+ :SSLClientCA => nil,
73
+ :SSLExtraChainCert => nil,
74
+ :SSLCACertificateFile => nil,
75
+ :SSLCACertificatePath => nil,
76
+ :SSLCertificateStore => nil,
77
+ :SSLTmpDhCallback => nil,
78
+ :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
79
+ :SSLVerifyDepth => nil,
80
+ :SSLVerifyCallback => nil, # custom verification
81
+ :SSLTimeout => nil,
82
+ :SSLOptions => nil,
83
+ :SSLCiphers => nil,
84
+ :SSLStartImmediately => true,
85
+ # Must specify if you use auto generated certificate.
86
+ :SSLCertName => nil,
87
+ :SSLCertComment => "Generated by Ruby/OpenSSL"
88
+ }
89
+ General.update(SSL)
90
+ end
91
+
92
+ module Utils
93
+ ##
94
+ # Creates a self-signed certificate with the given number of +bits+,
95
+ # the issuer +cn+ and a +comment+ to be stored in the certificate.
96
+
97
+ def create_self_signed_cert(bits, cn, comment)
98
+ rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
99
+ case p
100
+ when 0; $stderr.putc "." # BN_generate_prime
101
+ when 1; $stderr.putc "+" # BN_generate_prime
102
+ when 2; $stderr.putc "*" # searching good prime,
103
+ # n = #of try,
104
+ # but also data from BN_generate_prime
105
+ when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
106
+ # but also data from BN_generate_prime
107
+ else; $stderr.putc "*" # BN_generate_prime
108
+ end
109
+ }
110
+ cert = OpenSSL::X509::Certificate.new
111
+ cert.version = 2
112
+ cert.serial = 1
113
+ name = (cn.kind_of? String) ? OpenSSL::X509::Name.parse(cn)
114
+ : OpenSSL::X509::Name.new(cn)
115
+ cert.subject = name
116
+ cert.issuer = name
117
+ cert.not_before = Time.now
118
+ cert.not_after = Time.now + (365*24*60*60)
119
+ cert.public_key = rsa.public_key
120
+
121
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
122
+ ef.issuer_certificate = cert
123
+ cert.extensions = [
124
+ ef.create_extension("basicConstraints","CA:FALSE"),
125
+ ef.create_extension("keyUsage", "keyEncipherment, digitalSignature, keyAgreement, dataEncipherment"),
126
+ ef.create_extension("subjectKeyIdentifier", "hash"),
127
+ ef.create_extension("extendedKeyUsage", "serverAuth"),
128
+ ef.create_extension("nsComment", comment),
129
+ ]
130
+ aki = ef.create_extension("authorityKeyIdentifier",
131
+ "keyid:always,issuer:always")
132
+ cert.add_extension(aki)
133
+ cert.sign(rsa, "SHA256")
134
+
135
+ return [ cert, rsa ]
136
+ end
137
+ module_function :create_self_signed_cert
138
+ end
139
+
140
+ ##
141
+ #--
142
+ # Updates WEBrick::GenericServer with SSL functionality
143
+
144
+ class GenericServer
145
+
146
+ ##
147
+ # SSL context for the server when run in SSL mode
148
+
149
+ def ssl_context # :nodoc:
150
+ @ssl_context ||= begin
151
+ if @config[:SSLEnable]
152
+ ssl_context = setup_ssl_context(@config)
153
+ @logger.info("\n" + @config[:SSLCertificate].to_text)
154
+ ssl_context
155
+ end
156
+ end
157
+ end
158
+
159
+ undef listen
160
+
161
+ ##
162
+ # Updates +listen+ to enable SSL when the SSL configuration is active.
163
+
164
+ def listen(address, port) # :nodoc:
165
+ listeners = Utils::create_listeners(address, port)
166
+ if @config[:SSLEnable]
167
+ listeners.collect!{|svr|
168
+ ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
169
+ ssvr.start_immediately = @config[:SSLStartImmediately]
170
+ ssvr
171
+ }
172
+ end
173
+ @listeners += listeners
174
+ setup_shutdown_pipe
175
+ end
176
+
177
+ ##
178
+ # Sets up an SSL context for +config+
179
+
180
+ def setup_ssl_context(config) # :nodoc:
181
+ unless config[:SSLCertificate]
182
+ cn = config[:SSLCertName]
183
+ comment = config[:SSLCertComment]
184
+ cert, key = Utils::create_self_signed_cert(2048, cn, comment)
185
+ config[:SSLCertificate] = cert
186
+ config[:SSLPrivateKey] = key
187
+ end
188
+ ctx = OpenSSL::SSL::SSLContext.new
189
+ ctx.key = config[:SSLPrivateKey]
190
+ ctx.cert = config[:SSLCertificate]
191
+ ctx.client_ca = config[:SSLClientCA]
192
+ ctx.extra_chain_cert = config[:SSLExtraChainCert]
193
+ ctx.ca_file = config[:SSLCACertificateFile]
194
+ ctx.ca_path = config[:SSLCACertificatePath]
195
+ ctx.cert_store = config[:SSLCertificateStore]
196
+ ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
197
+ ctx.verify_mode = config[:SSLVerifyClient]
198
+ ctx.verify_depth = config[:SSLVerifyDepth]
199
+ ctx.verify_callback = config[:SSLVerifyCallback]
200
+ ctx.servername_cb = config[:SSLServerNameCallback] || proc { |args| ssl_servername_callback(*args) }
201
+ ctx.timeout = config[:SSLTimeout]
202
+ ctx.options = config[:SSLOptions]
203
+ ctx.ciphers = config[:SSLCiphers]
204
+ ctx
205
+ end
206
+
207
+ ##
208
+ # ServerNameIndication callback
209
+
210
+ def ssl_servername_callback(sslsocket, hostname = nil)
211
+ # default
212
+ end
213
+
214
+ end
215
+ end
@@ -0,0 +1,265 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # utils.rb -- Miscellaneous utilities
4
+ #
5
+ # Author: IPR -- Internet Programming with Ruby -- writers
6
+ # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
7
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
8
+ # reserved.
9
+ #
10
+ # $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $
11
+
12
+ require 'socket'
13
+ require 'io/nonblock'
14
+ require 'etc'
15
+
16
+ module WEBrick
17
+ module Utils
18
+ ##
19
+ # Sets IO operations on +io+ to be non-blocking
20
+ def set_non_blocking(io)
21
+ io.nonblock = true if io.respond_to?(:nonblock=)
22
+ end
23
+ module_function :set_non_blocking
24
+
25
+ ##
26
+ # Sets the close on exec flag for +io+
27
+ def set_close_on_exec(io)
28
+ io.close_on_exec = true if io.respond_to?(:close_on_exec=)
29
+ end
30
+ module_function :set_close_on_exec
31
+
32
+ ##
33
+ # Changes the process's uid and gid to the ones of +user+
34
+ def su(user)
35
+ if pw = Etc.getpwnam(user)
36
+ Process::initgroups(user, pw.gid)
37
+ Process::Sys::setgid(pw.gid)
38
+ Process::Sys::setuid(pw.uid)
39
+ else
40
+ warn("WEBrick::Utils::su doesn't work on this platform", uplevel: 1)
41
+ end
42
+ end
43
+ module_function :su
44
+
45
+ ##
46
+ # The server hostname
47
+ def getservername
48
+ Socket::gethostname
49
+ end
50
+ module_function :getservername
51
+
52
+ ##
53
+ # Creates TCP server sockets bound to +address+:+port+ and returns them.
54
+ #
55
+ # It will create IPV4 and IPV6 sockets on all interfaces.
56
+ def create_listeners(address, port)
57
+ unless port
58
+ raise ArgumentError, "must specify port"
59
+ end
60
+ sockets = Socket.tcp_server_sockets(address, port)
61
+ sockets = sockets.map {|s|
62
+ s.autoclose = false
63
+ ts = TCPServer.for_fd(s.fileno)
64
+ s.close
65
+ ts
66
+ }
67
+ return sockets
68
+ end
69
+ module_function :create_listeners
70
+
71
+ ##
72
+ # Characters used to generate random strings
73
+ RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
74
+ "0123456789" +
75
+ "abcdefghijklmnopqrstuvwxyz"
76
+
77
+ ##
78
+ # Generates a random string of length +len+
79
+ def random_string(len)
80
+ rand_max = RAND_CHARS.bytesize
81
+ ret = +""
82
+ len.times{ ret << RAND_CHARS[rand(rand_max)] }
83
+ ret
84
+ end
85
+ module_function :random_string
86
+
87
+ ###########
88
+
89
+ require "timeout"
90
+ require "singleton"
91
+
92
+ ##
93
+ # Class used to manage timeout handlers across multiple threads.
94
+ #
95
+ # Timeout handlers should be managed by using the class methods which are
96
+ # synchronized.
97
+ #
98
+ # id = TimeoutHandler.register(10, Timeout::Error)
99
+ # begin
100
+ # sleep 20
101
+ # puts 'foo'
102
+ # ensure
103
+ # TimeoutHandler.cancel(id)
104
+ # end
105
+ #
106
+ # will raise Timeout::Error
107
+ #
108
+ # id = TimeoutHandler.register(10, Timeout::Error)
109
+ # begin
110
+ # sleep 5
111
+ # puts 'foo'
112
+ # ensure
113
+ # TimeoutHandler.cancel(id)
114
+ # end
115
+ #
116
+ # will print 'foo'
117
+ #
118
+ class TimeoutHandler
119
+ include Singleton
120
+
121
+ ##
122
+ # Mutex used to synchronize access across threads
123
+ TimeoutMutex = Thread::Mutex.new # :nodoc:
124
+
125
+ ##
126
+ # Registers a new timeout handler
127
+ #
128
+ # +time+:: Timeout in seconds
129
+ # +exception+:: Exception to raise when timeout elapsed
130
+ def TimeoutHandler.register(seconds, exception)
131
+ at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds
132
+ instance.register(Thread.current, at, exception)
133
+ end
134
+
135
+ ##
136
+ # Cancels the timeout handler +id+
137
+ def TimeoutHandler.cancel(id)
138
+ instance.cancel(Thread.current, id)
139
+ end
140
+
141
+ def self.terminate
142
+ instance.terminate
143
+ end
144
+
145
+ ##
146
+ # Creates a new TimeoutHandler. You should use ::register and ::cancel
147
+ # instead of creating the timeout handler directly.
148
+ def initialize
149
+ TimeoutMutex.synchronize{
150
+ @timeout_info = Hash.new
151
+ }
152
+ @queue = Thread::Queue.new
153
+ @watcher = nil
154
+ end
155
+
156
+ # :nodoc:
157
+ private \
158
+ def watch
159
+ to_interrupt = []
160
+ while true
161
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
162
+ wakeup = nil
163
+ to_interrupt.clear
164
+ TimeoutMutex.synchronize{
165
+ @timeout_info.each {|thread, ary|
166
+ next unless ary
167
+ ary.each{|info|
168
+ time, exception = *info
169
+ if time < now
170
+ to_interrupt.push [thread, info.object_id, exception]
171
+ elsif !wakeup || time < wakeup
172
+ wakeup = time
173
+ end
174
+ }
175
+ }
176
+ }
177
+ to_interrupt.each {|arg| interrupt(*arg)}
178
+ if !wakeup
179
+ @queue.pop
180
+ elsif (wakeup -= now) > 0
181
+ begin
182
+ (th = Thread.start {@queue.pop}).join(wakeup)
183
+ ensure
184
+ th&.kill&.join
185
+ end
186
+ end
187
+ @queue.clear
188
+ end
189
+ end
190
+
191
+ # :nodoc:
192
+ private \
193
+ def watcher
194
+ (w = @watcher)&.alive? and return w # usual case
195
+ TimeoutMutex.synchronize{
196
+ (w = @watcher)&.alive? and next w # pathological check
197
+ @watcher = Thread.start(&method(:watch))
198
+ }
199
+ end
200
+
201
+ ##
202
+ # Interrupts the timeout handler +id+ and raises +exception+
203
+ def interrupt(thread, id, exception)
204
+ if cancel(thread, id) && thread.alive?
205
+ thread.raise(exception, "execution timeout")
206
+ end
207
+ end
208
+
209
+ ##
210
+ # Registers a new timeout handler
211
+ #
212
+ # +time+:: Timeout in seconds
213
+ # +exception+:: Exception to raise when timeout elapsed
214
+ def register(thread, time, exception)
215
+ info = nil
216
+ TimeoutMutex.synchronize{
217
+ (@timeout_info[thread] ||= []) << (info = [time, exception])
218
+ }
219
+ @queue.push nil
220
+ watcher
221
+ return info.object_id
222
+ end
223
+
224
+ ##
225
+ # Cancels the timeout handler +id+
226
+ def cancel(thread, id)
227
+ TimeoutMutex.synchronize{
228
+ if ary = @timeout_info[thread]
229
+ ary.delete_if{|info| info.object_id == id }
230
+ if ary.empty?
231
+ @timeout_info.delete(thread)
232
+ end
233
+ return true
234
+ end
235
+ return false
236
+ }
237
+ end
238
+
239
+ ##
240
+ def terminate
241
+ TimeoutMutex.synchronize{
242
+ @timeout_info.clear
243
+ @watcher&.kill&.join
244
+ }
245
+ end
246
+ end
247
+
248
+ ##
249
+ # Executes the passed block and raises +exception+ if execution takes more
250
+ # than +seconds+.
251
+ #
252
+ # If +seconds+ is zero or nil, simply executes the block
253
+ def timeout(seconds, exception=Timeout::Error)
254
+ return yield if seconds.nil? or seconds.zero?
255
+ # raise ThreadError, "timeout within critical session" if Thread.critical
256
+ id = TimeoutHandler.register(seconds, exception)
257
+ begin
258
+ yield(seconds)
259
+ ensure
260
+ TimeoutHandler.cancel(id)
261
+ end
262
+ end
263
+ module_function :timeout
264
+ end
265
+ end