github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/command/views/apply.go (about)

     1  package views
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/iaas-resource-provision/iaas-rpc/internal/command/arguments"
     7  	"github.com/iaas-resource-provision/iaas-rpc/internal/command/format"
     8  	"github.com/iaas-resource-provision/iaas-rpc/internal/command/views/json"
     9  	"github.com/iaas-resource-provision/iaas-rpc/internal/states"
    10  	"github.com/iaas-resource-provision/iaas-rpc/internal/terraform"
    11  	"github.com/iaas-resource-provision/iaas-rpc/internal/tfdiags"
    12  )
    13  
    14  // The Apply view is used for the apply command.
    15  type Apply interface {
    16  	ResourceCount(stateOutPath string)
    17  	Outputs(outputValues map[string]*states.OutputValue)
    18  
    19  	Operation() Operation
    20  	Hooks() []terraform.Hook
    21  
    22  	Diagnostics(diags tfdiags.Diagnostics)
    23  	HelpPrompt()
    24  }
    25  
    26  // NewApply returns an initialized Apply implementation for the given ViewType.
    27  func NewApply(vt arguments.ViewType, destroy bool, view *View) Apply {
    28  	switch vt {
    29  	case arguments.ViewJSON:
    30  		return &ApplyJSON{
    31  			view:      NewJSONView(view),
    32  			destroy:   destroy,
    33  			countHook: &countHook{},
    34  		}
    35  	case arguments.ViewHuman:
    36  		return &ApplyHuman{
    37  			view:         view,
    38  			destroy:      destroy,
    39  			inAutomation: view.RunningInAutomation(),
    40  			countHook:    &countHook{},
    41  		}
    42  	default:
    43  		panic(fmt.Sprintf("unknown view type %v", vt))
    44  	}
    45  }
    46  
    47  // The ApplyHuman implementation renders human-readable text logs, suitable for
    48  // a scrolling terminal.
    49  type ApplyHuman struct {
    50  	view *View
    51  
    52  	destroy      bool
    53  	inAutomation bool
    54  
    55  	countHook *countHook
    56  }
    57  
    58  var _ Apply = (*ApplyHuman)(nil)
    59  
    60  func (v *ApplyHuman) ResourceCount(stateOutPath string) {
    61  	if v.destroy {
    62  		v.view.streams.Printf(
    63  			v.view.colorize.Color("[reset][bold][green]\nDestroy complete! Resources: %d destroyed.\n"),
    64  			v.countHook.Removed,
    65  		)
    66  	} else {
    67  		v.view.streams.Printf(
    68  			v.view.colorize.Color("[reset][bold][green]\nApply complete! Resources: %d added, %d changed, %d destroyed.\n"),
    69  			v.countHook.Added,
    70  			v.countHook.Changed,
    71  			v.countHook.Removed,
    72  		)
    73  	}
    74  	if (v.countHook.Added > 0 || v.countHook.Changed > 0) && stateOutPath != "" {
    75  		v.view.streams.Printf("\n%s\n\n", format.WordWrap(stateOutPathPostApply, v.view.outputColumns()))
    76  		v.view.streams.Printf("State path: %s\n", stateOutPath)
    77  	}
    78  }
    79  
    80  func (v *ApplyHuman) Outputs(outputValues map[string]*states.OutputValue) {
    81  	if len(outputValues) > 0 {
    82  		v.view.streams.Print(v.view.colorize.Color("[reset][bold][green]\nOutputs:\n\n"))
    83  		NewOutput(arguments.ViewHuman, v.view).Output("", outputValues)
    84  	}
    85  }
    86  
    87  func (v *ApplyHuman) Operation() Operation {
    88  	return NewOperation(arguments.ViewHuman, v.inAutomation, v.view)
    89  }
    90  
    91  func (v *ApplyHuman) Hooks() []terraform.Hook {
    92  	return []terraform.Hook{
    93  		v.countHook,
    94  		NewUiHook(v.view),
    95  	}
    96  }
    97  
    98  func (v *ApplyHuman) Diagnostics(diags tfdiags.Diagnostics) {
    99  	v.view.Diagnostics(diags)
   100  }
   101  
   102  func (v *ApplyHuman) HelpPrompt() {
   103  	command := "apply"
   104  	if v.destroy {
   105  		command = "destroy"
   106  	}
   107  	v.view.HelpPrompt(command)
   108  }
   109  
   110  const stateOutPathPostApply = "The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the `terraform show` command."
   111  
   112  // The ApplyJSON implementation renders streaming JSON logs, suitable for
   113  // integrating with other software.
   114  type ApplyJSON struct {
   115  	view *JSONView
   116  
   117  	destroy bool
   118  
   119  	countHook *countHook
   120  }
   121  
   122  var _ Apply = (*ApplyJSON)(nil)
   123  
   124  func (v *ApplyJSON) ResourceCount(stateOutPath string) {
   125  	operation := json.OperationApplied
   126  	if v.destroy {
   127  		operation = json.OperationDestroyed
   128  	}
   129  	v.view.ChangeSummary(&json.ChangeSummary{
   130  		Add:       v.countHook.Added,
   131  		Change:    v.countHook.Changed,
   132  		Remove:    v.countHook.Removed,
   133  		Operation: operation,
   134  	})
   135  }
   136  
   137  func (v *ApplyJSON) Outputs(outputValues map[string]*states.OutputValue) {
   138  	outputs, diags := json.OutputsFromMap(outputValues)
   139  	if diags.HasErrors() {
   140  		v.Diagnostics(diags)
   141  	} else {
   142  		v.view.Outputs(outputs)
   143  	}
   144  }
   145  
   146  func (v *ApplyJSON) Operation() Operation {
   147  	return &OperationJSON{view: v.view}
   148  }
   149  
   150  func (v *ApplyJSON) Hooks() []terraform.Hook {
   151  	return []terraform.Hook{
   152  		v.countHook,
   153  		newJSONHook(v.view),
   154  	}
   155  }
   156  
   157  func (v *ApplyJSON) Diagnostics(diags tfdiags.Diagnostics) {
   158  	v.view.Diagnostics(diags)
   159  }
   160  
   161  func (v *ApplyJSON) HelpPrompt() {
   162  }