Class: Boxd::CLIBackend
- Inherits:
-
Object
- Object
- Boxd::CLIBackend
- Defined in:
- lib/boxd/cli_backend.rb
Overview
CLIBackend shells out to the ‘boxd` CLI for every operation. v0 of this gem is built on this; v1 will speak gRPC directly. The public API does not change between the two — only this file does.
Constant Summary collapse
- DEFAULT_BIN =
"boxd"
Instance Attribute Summary collapse
-
#bin ⇒ Object
readonly
Returns the value of attribute bin.
-
#env ⇒ Object
readonly
Returns the value of attribute env.
Instance Method Summary collapse
-
#call_json(*args) ⇒ Object
Run ‘boxd <args>` and parse `–json` output.
-
#call_raw(*args) ⇒ Object
Run ‘boxd <args>` and return [stdout, stderr] as strings.
-
#exec_stream(vm, cmd, env: nil, tty: false, &block) ⇒ Object
Stream ‘boxd exec` for a single command, yielding chunks.
-
#initialize(api_key: nil, bin: nil, environment: nil) ⇒ CLIBackend
constructor
A new instance of CLIBackend.
Constructor Details
#initialize(api_key: nil, bin: nil, environment: nil) ⇒ CLIBackend
Returns a new instance of CLIBackend.
17 18 19 20 21 22 23 24 |
# File 'lib/boxd/cli_backend.rb', line 17 def initialize(api_key: nil, bin: nil, environment: nil) @bin = bin || ENV["BOXD_BIN"] || DEFAULT_BIN @env = {} @env["BOXD_TOKEN"] = api_key if api_key @env["BOXD_ENVIRONMENT"] = environment if environment assert_cli_present! end |
Instance Attribute Details
#bin ⇒ Object (readonly)
Returns the value of attribute bin.
15 16 17 |
# File 'lib/boxd/cli_backend.rb', line 15 def bin @bin end |
#env ⇒ Object (readonly)
Returns the value of attribute env.
15 16 17 |
# File 'lib/boxd/cli_backend.rb', line 15 def env @env end |
Instance Method Details
#call_json(*args) ⇒ Object
Run ‘boxd <args>` and parse `–json` output. Raises on non-zero exit with a typed Boxd::Error subclass when we recognise the failure.
28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/boxd/cli_backend.rb', line 28 def call_json(*args) out, err, status = Open3.capture3(env, bin, "--json", *args.map(&:to_s)) unless status.success? raise classify_error(err.empty? ? out : err, args) end return nil if out.strip.empty? JSON.parse(out, symbolize_names: true) rescue JSON::ParserError => e raise InternalError, "boxd CLI returned non-JSON output for `#{args.join(' ')}`: #{e.}\n#{out}" end |
#call_raw(*args) ⇒ Object
Run ‘boxd <args>` and return [stdout, stderr] as strings. Used for commands without –json support.
43 44 45 46 47 48 |
# File 'lib/boxd/cli_backend.rb', line 43 def call_raw(*args) out, err, status = Open3.capture3(env, bin, *args.map(&:to_s)) raise classify_error(err.empty? ? out : err, args) unless status.success? [out, err] end |
#exec_stream(vm, cmd, env: nil, tty: false, &block) ⇒ Object
Stream ‘boxd exec` for a single command, yielding chunks. Returns the exit code captured from CLI exit status.
The CLI does not stream stdout/stderr separately by default; we capture both via pipes and yield each line as it arrives, tagging the stream.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/boxd/cli_backend.rb', line 56 def exec_stream(vm, cmd, env: nil, tty: false, &block) cli_args = ["exec"] cli_args << "--tty" if tty Array(env).each do |k, v| cli_args.push("-e", "#{k}=#{v}") end cli_args << vm.to_s cli_args << "--" cli_args.concat(Array(cmd).map(&:to_s)) stdout_buf = +"" stderr_buf = +"" exit_code = nil Open3.popen3(self.env, bin, *cli_args) do |_stdin, stdout, stderr, wait_thr| threads = [] threads << Thread.new do stdout.each_line do |line| stdout_buf << line block&.call(:stdout, line) end end threads << Thread.new do stderr.each_line do |line| stderr_buf << line block&.call(:stderr, line) end end threads.each(&:join) exit_code = wait_thr.value.exitstatus end { stdout: stdout_buf, stderr: stderr_buf, exit_code: exit_code } end |