core: add a context to the UIInput interface

pull/20616/head
Sander van Harmelen 7 years ago
parent fc531f54a8
commit 1e057dc5ce

@ -107,7 +107,7 @@ func (b *Local) opApply(
b.CLI.Output("")
}
v, err := op.UIIn.Input(&terraform.InputOpts{
v, err := op.UIIn.Input(stopCtx, &terraform.InputOpts{
Id: "approve",
Query: query,
Description: desc,

@ -638,13 +638,13 @@ func (b *Remote) Operation(ctx context.Context, op *backend.Operation) (*backend
}
func (b *Remote) cancel(cancelCtx context.Context, op *backend.Operation, r *tfe.Run) error {
if r.Status == tfe.RunPending && r.Actions.IsCancelable {
if r.Actions.IsCancelable {
// Only ask if the remote operation should be canceled
// if the auto approve flag is not set.
if !op.AutoApprove {
v, err := op.UIIn.Input(&terraform.InputOpts{
v, err := op.UIIn.Input(cancelCtx, &terraform.InputOpts{
Id: "cancel",
Query: "\nDo you want to cancel the pending remote operation?",
Query: "\nDo you want to cancel the remote operation?",
Description: "Only 'yes' will be accepted to cancel.",
})
if err != nil {

@ -284,7 +284,7 @@ func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Ope
}
func (b *Remote) confirm(stopCtx context.Context, op *backend.Operation, opts *terraform.InputOpts, r *tfe.Run, keyword string) error {
v, err := op.UIIn.Input(opts)
v, err := op.UIIn.Input(stopCtx, opts)
if err != nil {
return fmt.Errorf("Error asking %s: %v", opts.Id, err)
}

@ -217,7 +217,7 @@ type mockInput struct {
answers map[string]string
}
func (m *mockInput) Input(opts *terraform.InputOpts) (string, error) {
func (m *mockInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
v, ok := m.answers[opts.Id]
if !ok {
return "", fmt.Errorf("unexpected input request in test: %s", opts.Id)

@ -124,7 +124,7 @@ type Meta struct {
//
// stateOutPath is used to override the output path for the state.
// If not provided, the StatePath is used causing the old state to
// be overriden.
// be overridden.
//
// backupPath is used to backup the state file before writing a modified
// version. It defaults to stateOutPath + DefaultBackupExtension
@ -508,7 +508,7 @@ func (m *Meta) confirm(opts *terraform.InputOpts) (bool, error) {
}
for i := 0; i < 2; i++ {
v, err := m.UIInput().Input(opts)
v, err := m.UIInput().Input(context.Background(), opts)
if err != nil {
return false, fmt.Errorf(
"Error asking for confirmation: %s", err)

@ -201,7 +201,7 @@ func (m *Meta) selectWorkspace(b backend.Backend) error {
// If the selected workspace is not migrated, ask the user to select
// a workspace from the list of migrated workspaces.
v, err := m.UIInput().Input(&terraform.InputOpts{
v, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
Id: "select-workspace",
Query: fmt.Sprintf(
"[reset][bold][yellow]The currently selected workspace (%s) is not migrated.[reset]",
@ -280,7 +280,7 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
// If the backend doesn't support using the default state, we ask the user
// for a new name and migrate the default state to the given named state.
stateTwo, err = func() (state.State, error) {
name, err := m.UIInput().Input(&terraform.InputOpts{
name, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
Id: "new-state-name",
Query: fmt.Sprintf(
"[reset][bold][yellow]The %q backend configuration only allows "+

@ -3,6 +3,7 @@ package command
import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"io"
@ -38,7 +39,7 @@ type UIInput struct {
once sync.Once
}
func (i *UIInput) Input(opts *terraform.InputOpts) (string, error) {
func (i *UIInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
i.once.Do(i.init)
r := i.Reader
@ -137,6 +138,12 @@ func (i *UIInput) Input(opts *terraform.InputOpts) (string, error) {
}
return line, nil
case <-ctx.Done():
// Print a newline so that any further output starts properly
// on a new line.
fmt.Fprintln(w)
return "", ctx.Err()
case <-sigCh:
// Print a newline so that any further output starts properly
// on a new line.

@ -2,6 +2,7 @@ package command
import (
"bytes"
"context"
"testing"
"github.com/hashicorp/terraform/terraform"
@ -17,7 +18,7 @@ func TestUIInputInput(t *testing.T) {
Writer: bytes.NewBuffer(nil),
}
v, err := i.Input(&terraform.InputOpts{})
v, err := i.Input(context.Background(), &terraform.InputOpts{})
if err != nil {
t.Fatalf("err: %s", err)
}
@ -33,7 +34,7 @@ func TestUIInputInput_spaces(t *testing.T) {
Writer: bytes.NewBuffer(nil),
}
v, err := i.Input(&terraform.InputOpts{})
v, err := i.Input(context.Background(), &terraform.InputOpts{})
if err != nil {
t.Fatalf("err: %s", err)
}

@ -1,6 +1,7 @@
package command
import (
"context"
"fmt"
"strings"
@ -90,7 +91,7 @@ func (c *UnlockCommand) Run(args []string) int {
"This will allow local Terraform commands to modify this state, even though it\n" +
"may be still be in use. Only 'yes' will be accepted to confirm."
v, err := c.UIInput().Input(&terraform.InputOpts{
v, err := c.UIInput().Input(context.Background(), &terraform.InputOpts{
Id: "force-unlock",
Query: "Do you really want to force-unlock?",
Description: desc,

@ -12,6 +12,7 @@
package schema
import (
"context"
"fmt"
"os"
"reflect"
@ -1210,7 +1211,7 @@ func (m schemaMap) inputString(
input terraform.UIInput,
k string,
schema *Schema) (interface{}, error) {
result, err := input.Input(&terraform.InputOpts{
result, err := input.Input(context.Background(), &terraform.InputOpts{
Id: k,
Query: k,
Description: schema.Description,

@ -1,19 +1,20 @@
package plugin
import (
"context"
"net/rpc"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/terraform"
)
// UIInput is an implementatin of terraform.UIInput that communicates
// UIInput is an implementation of terraform.UIInput that communicates
// over RPC.
type UIInput struct {
Client *rpc.Client
}
func (i *UIInput) Input(opts *terraform.InputOpts) (string, error) {
func (i *UIInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
var resp UIInputInputResponse
err := i.Client.Call("Plugin.Input", opts, &resp)
if err != nil {
@ -41,7 +42,7 @@ type UIInputServer struct {
func (s *UIInputServer) Input(
opts *terraform.InputOpts,
reply *UIInputInputResponse) error {
value, err := s.UIInput.Input(opts)
value, err := s.UIInput.Input(context.Background(), opts)
*reply = UIInputInputResponse{
Value: value,
Error: plugin.NewBasicError(err),

@ -1,6 +1,7 @@
package plugin
import (
"context"
"reflect"
"testing"
@ -32,7 +33,7 @@ func TestUIInput_input(t *testing.T) {
Id: "foo",
}
v, err := input.Input(opts)
v, err := input.Input(context.Background(), opts)
if !i.InputCalled {
t.Fatal("input should be called")
}

@ -182,7 +182,7 @@ func TestLookupLookupModuleError(t *testing.T) {
client := NewClient(test.Disco(server), nil)
// this should not be found in teh registry
// this should not be found in the registry
src := "bad/local/path"
mod, err := regsrc.ParseModuleSource(src)
if err != nil {

@ -8,12 +8,11 @@ import (
"strings"
"sync"
"github.com/hashicorp/terraform/tfdiags"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/tfdiags"
"github.com/hashicorp/terraform/version"
)
@ -415,7 +414,7 @@ func (c *Context) Input(mode InputMode) error {
retry := 0
for {
var err error
value, err = c.uiInput.Input(&InputOpts{
value, err = c.uiInput.Input(context.Background(), &InputOpts{
Id: fmt.Sprintf("var.%s", n),
Query: fmt.Sprintf("var.%s", n),
Description: v.Description,

@ -1,6 +1,7 @@
package terraform
import (
"context"
"errors"
"reflect"
"strings"
@ -251,7 +252,7 @@ func TestContext2Input_providerId(t *testing.T) {
var actual interface{}
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
v, err := i.Input(&InputOpts{Id: "foo"})
v, err := i.Input(context.Background(), &InputOpts{Id: "foo"})
if err != nil {
return nil, err
}

@ -1,10 +1,12 @@
package terraform
import "context"
// UIInput is the interface that must be implemented to ask for input
// from this user. This should forward the request to wherever the user
// inputs things to ask for values.
type UIInput interface {
Input(*InputOpts) (string, error)
Input(context.Context, *InputOpts) (string, error)
}
// InputOpts are options for asking for input.

@ -1,5 +1,7 @@
package terraform
import "context"
// MockUIInput is an implementation of UIInput that can be used for tests.
type MockUIInput struct {
InputCalled bool
@ -10,7 +12,7 @@ type MockUIInput struct {
InputFn func(*InputOpts) (string, error)
}
func (i *MockUIInput) Input(opts *InputOpts) (string, error) {
func (i *MockUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
i.InputCalled = true
i.InputOpts = opts
if i.InputFn != nil {

@ -1,6 +1,7 @@
package terraform
import (
"context"
"fmt"
)
@ -12,8 +13,8 @@ type PrefixUIInput struct {
UIInput UIInput
}
func (i *PrefixUIInput) Input(opts *InputOpts) (string, error) {
func (i *PrefixUIInput) Input(ctx context.Context, opts *InputOpts) (string, error) {
opts.Id = fmt.Sprintf("%s.%s", i.IdPrefix, opts.Id)
opts.Query = fmt.Sprintf("%s%s", i.QueryPrefix, opts.Query)
return i.UIInput.Input(opts)
return i.UIInput.Input(ctx, opts)
}

@ -1,6 +1,7 @@
package terraform
import (
"context"
"testing"
)
@ -15,7 +16,7 @@ func testPrefixUIInput(t *testing.T) {
UIInput: input,
}
_, err := prefix.Input(&InputOpts{Id: "bar"})
_, err := prefix.Input(context.Background(), &InputOpts{Id: "bar"})
if err != nil {
t.Fatalf("err: %s", err)
}

Loading…
Cancel
Save