Module: SimpleCov::CLI::Serve
- Extended by:
- CommandHelpers, Serve
- Included in:
- Serve
- Defined in:
- lib/simplecov/cli/serve.rb,
lib/simplecov/cli/serve/report_preparer.rb,
lib/simplecov/cli/serve/static_file_handler.rb
Overview
simplecov serve: a small static file server backed by stdlib socket, so
there is no extra dependency just for viewing a local report on a box where
file:// doesn't work. This module is the CLI wiring; the HTTP mechanics
live in StaticFileHandler.
Defined Under Namespace
Modules: ReportPreparer, StaticFileHandler
Constant Summary
Constants included from CommandHelpers
CommandHelpers::STATS_ROW_FORMAT
Instance Method Summary collapse
- #announce(stdout, server, dir) ⇒ Object
- #parse(args) ⇒ Object
-
#require_socket ⇒ Object
Required here rather than at load time so the other subcommands do not pay for sockets.
- #run(args, stdout:, stderr:) ⇒ Object
-
#serve_loop(server, dir, stdout) ⇒ Object
One thread per connection: browsers open speculative sockets that send no bytes, and a serial loop would stall every real request behind them.
-
#url_host(host) ⇒ Object
IPv6 literals need brackets in a URL:
--host ::1must announce http://[::1]:PORT/, not the invalid http://::1:PORT/. -
#with_server(opts, stderr) ⇒ Object
Answers 1 when the socket can't be bound: port already taken, privileged port, unresolvable host.
Methods included from CommandHelpers
build_parser, command_name, common_options, error, error_nil, on_help, one?, parse_common, quiet_option, recorded_contexts, stats_row
Instance Method Details
#announce(stdout, server, dir) ⇒ Object
64 65 66 67 68 69 |
# File 'lib/simplecov/cli/serve.rb', line 64 def announce(stdout, server, dir) port = server.addr.fetch(1) host = url_host(server.addr.fetch(3)) stdout.puts("simplecov serve: serving #{dir} at http://#{host}:#{port}/") stdout.puts("Press Ctrl-C to stop.") end |
#parse(args) ⇒ Object
55 56 57 58 59 60 61 62 |
# File 'lib/simplecov/cli/serve.rb', line 55 def parse(args) opts = {port: 0, host: "127.0.0.1"} #: Hash[Symbol, untyped] build_parser do |o| o.on("--port N", Integer) { |v| opts[:port] = v } o.on("--host HOST") { |v| opts[:host] = v } end.parse(args) opts end |
#require_socket ⇒ Object
Required here rather than at load time so the other subcommands do not pay for sockets.
35 36 37 |
# File 'lib/simplecov/cli/serve.rb', line 35 def require_socket require "socket" end |
#run(args, stdout:, stderr:) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/simplecov/cli/serve.rb', line 19 def run(args, stdout:, stderr:, **) opts = parse(args) dir = CLI.coverage_dir = ReportPreparer.call(dir) return error(stderr, ) if require_socket with_server(opts, stderr) do |server| announce(stdout, server, dir) serve_loop(server, dir, stdout) 0 end end |
#serve_loop(server, dir, stdout) ⇒ Object
One thread per connection: browsers open speculative sockets that send no bytes, and a serial loop would stall every real request behind them.
79 80 81 82 83 84 85 |
# File 'lib/simplecov/cli/serve.rb', line 79 def serve_loop(server, dir, stdout) loop do Thread.new(server.accept) { |client| StaticFileHandler.handle_connection(client, dir) } end rescue Interrupt stdout.puts("\nsimplecov serve: stopping") end |
#url_host(host) ⇒ Object
IPv6 literals need brackets in a URL: --host ::1 must announce
http://[::1]:PORT/, not the invalid http://::1:PORT/.
73 74 75 |
# File 'lib/simplecov/cli/serve.rb', line 73 def url_host(host) host.include?(":") ? "[#{host}]" : host end |
#with_server(opts, stderr) ⇒ Object
Answers 1 when the socket can't be bound: port already taken, privileged
port, unresolvable host. The receiver cast works around an rbs stdlib gap,
where TCPSocket's explicit self.new shadows TCPServer#initialize's
(host, port) form.
43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/simplecov/cli/serve.rb', line 43 def with_server(opts, stderr) server = (_ = TCPServer).new(opts.fetch(:host), opts.fetch(:port)) #: TCPServer rescue SystemCallError, SocketError => e error(stderr, "cannot bind to #{opts.fetch(:host)}:#{opts.fetch(:port)} (#{e})") else begin yield server ensure server.close end end |