Module: SimpleCov::CLI::Serve
- Extended by:
- CommandHelpers
- 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 [--port N] [--host HOST] — serve the coverage
report over HTTP. A small static file server backed by stdlib
socket, so there's no extra dependency just for "view a local
report on a CI box where file:// doesn't work." This module is
the CLI wiring (options, binding, the accept loop); the HTTP
mechanics live in StaticFileHandler.
Defined Under Namespace
Modules: ReportPreparer, StaticFileHandler
Constant Summary
Constants included from CommandHelpers
CommandHelpers::STATS_ROW_FORMAT
Class Method Summary collapse
- .announce(stdout, server, dir) ⇒ Object
- .parse(args) ⇒ Object
- .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 (the report's assets included) behind them.
-
.url_host(host) ⇒ Object
IPv6 literals need brackets in a URL (--host ::1 must announce http://[::1]:PORT/, not the invalid http://::1:PORT/).
-
.with_server(opts, stderr) ⇒ Object
Returns the block's exit status, or 1 when the socket can't be bound (port already taken, privileged port, unresolvable host).
Methods included from CommandHelpers
command_name, common_options, error, parse_common, stats_row
Class Method Details
.announce(stdout, server, dir) ⇒ Object
60 61 62 63 64 65 |
# File 'lib/simplecov/cli/serve.rb', line 60 def announce(stdout, server, dir) port = server.addr[1] host = url_host(server.addr[3]) stdout.puts("simplecov serve: serving #{dir} at http://#{host}:#{port}/") stdout.puts("Press Ctrl-C to stop.") end |
.parse(args) ⇒ Object
51 52 53 54 55 56 57 58 |
# File 'lib/simplecov/cli/serve.rb', line 51 def parse(args) opts = {port: 0, host: "127.0.0.1"} #: Hash[Symbol, untyped] OptionParser.new do |o| o.on("--port N", Integer) { |v| opts[:port] = v } o.on("--host HOST") { |v| opts[:host] = v } end.parse(args) opts end |
.run(args, stdout:, stderr:) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/simplecov/cli/serve.rb', line 21 def run(args, stdout:, stderr:, **) opts = parse(args) dir = SimpleCov::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 (the report's assets included) behind them.
76 77 78 79 80 81 82 |
# File 'lib/simplecov/cli/serve.rb', line 76 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/).
69 70 71 |
# File 'lib/simplecov/cli/serve.rb', line 69 def url_host(host) host.include?(":") ? "[#{host}]" : host end |
.with_server(opts, stderr) ⇒ Object
Returns the block's exit status, or 1 when the socket can't be bound (port already taken, privileged port, unresolvable host).
37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/simplecov/cli/serve.rb', line 37 def with_server(opts, stderr) # The receiver cast works around an rbs stdlib gap: TCPSocket's # explicit `self.new` shadows TCPServer#initialize's (host, port) form. server = (_ = TCPServer).new(opts[:host], opts[:port]) #: TCPServer rescue SystemCallError, SocketError => e error(stderr, "cannot bind to #{opts[:host]}:#{opts[:port]} (#{e.})") else begin yield server ensure server.close end end |