2016-11-14 07:04:21 +01:00
|
|
|
package repl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"strings"
|
|
|
|
|
2018-05-04 05:44:55 +02:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
|
2019-09-10 00:58:44 +02:00
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
|
|
"github.com/hashicorp/hcl/v2/hclsyntax"
|
2018-05-04 05:44:55 +02:00
|
|
|
"github.com/hashicorp/terraform/lang"
|
|
|
|
"github.com/hashicorp/terraform/tfdiags"
|
2016-11-14 07:04:21 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// ErrSessionExit is a special error result that should be checked for
|
|
|
|
// from Handle to signal a graceful exit.
|
|
|
|
var ErrSessionExit = errors.New("session exit")
|
|
|
|
|
|
|
|
// Session represents the state for a single REPL session.
|
|
|
|
type Session struct {
|
2018-05-04 05:44:55 +02:00
|
|
|
// Scope is the evaluation scope where expressions will be evaluated.
|
|
|
|
Scope *lang.Scope
|
2016-11-14 07:04:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle handles a single line of input from the REPL.
|
|
|
|
//
|
|
|
|
// This is a stateful operation if a command is given (such as setting
|
|
|
|
// a variable). This function should not be called in parallel.
|
|
|
|
//
|
|
|
|
// The return value is the output and the error to show.
|
2018-05-04 05:44:55 +02:00
|
|
|
func (s *Session) Handle(line string) (string, bool, tfdiags.Diagnostics) {
|
2016-11-14 07:04:21 +01:00
|
|
|
switch {
|
2018-05-04 05:44:55 +02:00
|
|
|
case strings.TrimSpace(line) == "":
|
|
|
|
return "", false, nil
|
2016-11-14 07:04:21 +01:00
|
|
|
case strings.TrimSpace(line) == "exit":
|
2018-05-04 05:44:55 +02:00
|
|
|
return "", true, nil
|
2016-11-14 07:04:21 +01:00
|
|
|
case strings.TrimSpace(line) == "help":
|
2018-05-04 05:44:55 +02:00
|
|
|
ret, diags := s.handleHelp()
|
|
|
|
return ret, false, diags
|
2016-11-14 07:04:21 +01:00
|
|
|
default:
|
2018-05-04 05:44:55 +02:00
|
|
|
ret, diags := s.handleEval(line)
|
|
|
|
return ret, false, diags
|
2016-11-14 07:04:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-04 05:44:55 +02:00
|
|
|
func (s *Session) handleEval(line string) (string, tfdiags.Diagnostics) {
|
|
|
|
var diags tfdiags.Diagnostics
|
2016-11-14 07:04:21 +01:00
|
|
|
|
2018-05-04 05:44:55 +02:00
|
|
|
// Parse the given line as an expression
|
|
|
|
expr, parseDiags := hclsyntax.ParseExpression([]byte(line), "<console-input>", hcl.Pos{Line: 1, Column: 1})
|
|
|
|
diags = diags.Append(parseDiags)
|
|
|
|
if parseDiags.HasErrors() {
|
|
|
|
return "", diags
|
2016-11-14 07:04:21 +01:00
|
|
|
}
|
|
|
|
|
2018-05-04 05:44:55 +02:00
|
|
|
val, valDiags := s.Scope.EvalExpr(expr, cty.DynamicPseudoType)
|
|
|
|
diags = diags.Append(valDiags)
|
|
|
|
if valDiags.HasErrors() {
|
|
|
|
return "", diags
|
2016-11-14 07:04:21 +01:00
|
|
|
}
|
|
|
|
|
2020-09-09 20:13:53 +02:00
|
|
|
return FormatValue(val, 0), diags
|
2016-11-14 07:04:21 +01:00
|
|
|
}
|
|
|
|
|
2018-05-04 05:44:55 +02:00
|
|
|
func (s *Session) handleHelp() (string, tfdiags.Diagnostics) {
|
2016-11-14 07:04:21 +01:00
|
|
|
text := `
|
|
|
|
The Terraform console allows you to experiment with Terraform interpolations.
|
|
|
|
You may access resources in the state (if you have one) just as you would
|
|
|
|
from a configuration. For example: "aws_instance.foo.id" would evaluate
|
|
|
|
to the ID of "aws_instance.foo" if it exists in your state.
|
|
|
|
|
|
|
|
Type in the interpolation to test and hit <enter> to see the result.
|
|
|
|
|
|
|
|
To exit the console, type "exit" and hit <enter>, or use Control-C or
|
|
|
|
Control-D.
|
|
|
|
`
|
|
|
|
|
|
|
|
return strings.TrimSpace(text), nil
|
|
|
|
}
|