Skip to content

Commit

Permalink
Be more explicit when capturing and processing output.
Browse files Browse the repository at this point in the history
  • Loading branch information
tobyclemson committed Jul 9, 2024
1 parent b8eceed commit f9e7658
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 126 deletions.
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ PATH
specs:
ruby-terraform (1.8.0.pre.7)
immutable-struct (~> 2.4)
lino (= 3.2.0.pre.7)
lino (= 3.2.0.pre.9)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -31,7 +31,7 @@ GEM
diff-lcs (1.5.1)
docile (1.4.0)
drb (2.2.1)
excon (0.110.0)
excon (0.111.0)
faker (3.4.1)
i18n (>= 1.8.11, < 2)
faraday (2.10.0)
Expand Down Expand Up @@ -66,7 +66,7 @@ GEM
immutable-struct (2.4.1)
json (2.7.2)
language_server-protocol (3.17.0.3)
lino (3.2.0.pre.7)
lino (3.2.0.pre.9)
childprocess (~> 5.0.0)
hamster (~> 3.0)
open4 (~> 1.3)
Expand Down
98 changes: 72 additions & 26 deletions lib/ruby_terraform/commands/base.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'lino'
require 'tempfile'

require_relative '../errors'

Expand All @@ -12,12 +13,12 @@ class Base
# Constructs an instance of the command.
#
def initialize(opts = {})
@binary = opts[:binary] || RubyTerraform.configuration.binary
@logger = opts[:logger] || RubyTerraform.configuration.logger
@binary = opts[:binary] || RubyTerraform.configuration.binary
@logger = opts[:logger] || RubyTerraform.configuration.logger
@options = opts[:options] || RubyTerraform.configuration.options
@stdin = opts[:stdin] || RubyTerraform.configuration.stdin
@stdout = opts[:stdout] || RubyTerraform.configuration.stdout
@stderr = opts[:stderr] || RubyTerraform.configuration.stderr
@stdin = opts[:stdin] || RubyTerraform.configuration.stdin
@stdout = opts[:stdout] || RubyTerraform.configuration.stdout
@stderr = opts[:stderr] || RubyTerraform.configuration.stderr
end

# rubocop:enable Metrics/AbcSize
Expand All @@ -32,30 +33,24 @@ def initialize(opts = {})
# @option invocation_options [Hash<String, String>] :environment A map
# of environment variables to expose at command invocation time.
def execute(parameters = {}, invocation_options = {})
parameters = resolve_parameters(parameters)
invocation_options = resolve_invocation_options(invocation_options)

do_before(parameters)
build_and_execute_command(parameters, invocation_options)
result = build_and_execute_command(parameters, invocation_options)
do_after(parameters)

prepare_result(result, parameters, invocation_options)
rescue Lino::Errors::ExecutionError
message = "Failed while running '#{command_name}'."
logger.error(message)
raise Errors::ExecutionError, message
end

protected
private

attr_reader :binary, :logger, :stdin, :stdout, :stderr

def build_and_execute_command(parameters, invocation_options)
command = build_command(parameters, invocation_options)

logger.debug("Running '#{command}'.")
command.execute(
stdin:,
stdout:,
stderr:
)
end

def command_name
self.class.to_s.split('::')[-1].downcase
end
Expand All @@ -64,11 +59,7 @@ def do_before(_parameters); end

def do_after(_parameters); end

private

def build_command(parameters, invocation_options)
parameters = resolve_parameters(parameters)

Lino::CommandLineBuilder
.for_command(@binary)
.with_environment_variables(invocation_options[:environment] || {})
Expand All @@ -80,10 +71,8 @@ def build_command(parameters, invocation_options)
.build
end

def resolve_parameters(parameters)
parameter_defaults(parameters)
.merge(parameters)
.merge(parameter_overrides(parameters))
def process_result(result, _parameters, _invocation_options)
result
end

def parameter_defaults(_parameters)
Expand All @@ -94,6 +83,10 @@ def parameter_overrides(_parameters)
{}
end

def invocation_option_defaults(_invocation_options)
{ capture: [], result: :processed }
end

def subcommands
[]
end
Expand All @@ -105,6 +98,59 @@ def options
def arguments(_parameters)
[]
end

def build_and_execute_command(parameters, invocation_options)
command = build_command(parameters, invocation_options)
stdout = resolve_stdout(invocation_options)
stderr = resolve_stderr(invocation_options)

logger.debug("Running '#{command}'.")
command.execute(stdin:, stdout:, stderr:)

process_streams(invocation_options, stdout, stderr)
end

def resolve_parameters(parameters)
parameter_defaults(parameters)
.merge(parameters)
.merge(parameter_overrides(parameters))
end

def resolve_invocation_options(invocation_options)
invocation_option_defaults(invocation_options)
.merge(invocation_options)
end

def resolve_stdout(invocation_options)
invocation_options[:capture].include?(:stdout) ? Tempfile.new : @stdout
end

def resolve_stderr(invocation_options)
invocation_options[:capture].include?(:stderr) ? Tempfile.new : @stderr
end

def process_streams(invocation_options, stdout, stderr)
cap = invocation_options[:capture]

return nil if cap == []

result = {}
result = add_contents_to_result(cap, result, :stdout, stdout, :output)
add_contents_to_result(cap, result, :stderr, stderr, :error)
end

def add_contents_to_result(capture, result, stream_name, stream, type)
return result unless capture.include?(stream_name)

stream.rewind
result.merge({ type => stream.read })
end

def prepare_result(result, parameters, invocation_options)
return result if invocation_options[:result] == :raw

process_result(result, parameters, invocation_options)
end
end
end
end
9 changes: 4 additions & 5 deletions lib/ruby_terraform/commands/output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class Output < Base
include RubyTerraform::Options::Global

# @!visibility private
def stdout
@stdout.respond_to?(:string) ? @stdout : (@stdout = StringIO.new)
def invocation_option_defaults(invocation_options)
super.merge(capture: [:stdout])
end

# @!visibility private
Expand All @@ -67,9 +67,8 @@ def arguments(parameters)
end

# @!visibility private
def do_after(parameters)
result = stdout.string
parameters[:name] ? result.chomp : result
def process_result(result, parameters, _invocation_options)
parameters[:name] ? result[:output].chomp : result[:output]
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion ruby_terraform.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = '>= 3.1'

spec.add_dependency 'immutable-struct', '~> 2.4'
spec.add_dependency 'lino', '3.2.0.pre.7'
spec.add_dependency 'lino', '3.2.0.pre.9'

spec.add_development_dependency 'bundler'
spec.add_development_dependency 'faker'
Expand Down
Loading

0 comments on commit f9e7658

Please sign in to comment.