113 lines
3.4 KiB
Go
113 lines
3.4 KiB
Go
package cloud
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/hashicorp/go-tfe"
|
|
"github.com/hashicorp/terraform/internal/backend"
|
|
"github.com/mitchellh/cli"
|
|
)
|
|
|
|
// IntegrationOutputWriter is an interface used to to write output tailored for
|
|
// Terraform Cloud integrations
|
|
type IntegrationOutputWriter interface {
|
|
End()
|
|
OutputElapsed(message string, maxMessage int)
|
|
Output(str string)
|
|
SubOutput(str string)
|
|
}
|
|
|
|
// IntegrationContext is a set of data that is useful when performing Terraform Cloud integration operations
|
|
type IntegrationContext struct {
|
|
B *Cloud
|
|
StopContext context.Context
|
|
CancelContext context.Context
|
|
Op *backend.Operation
|
|
Run *tfe.Run
|
|
}
|
|
|
|
// integrationCLIOutput implements IntegrationOutputWriter
|
|
type integrationCLIOutput struct {
|
|
CLI cli.Ui
|
|
Colorizer Colorer
|
|
started time.Time
|
|
}
|
|
|
|
var _ IntegrationOutputWriter = (*integrationCLIOutput)(nil) // Compile time check
|
|
|
|
func (s *IntegrationContext) Poll(every func(i int) (bool, error)) error {
|
|
for i := 0; ; i++ {
|
|
select {
|
|
case <-s.StopContext.Done():
|
|
return s.StopContext.Err()
|
|
case <-s.CancelContext.Done():
|
|
return s.CancelContext.Err()
|
|
case <-time.After(backoff(backoffMin, backoffMax, i)):
|
|
// blocks for a time between min and max
|
|
}
|
|
|
|
cont, err := every(i)
|
|
if !cont {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
// BeginOutput writes a preamble to the CLI and creates a new IntegrationOutputWriter interface
|
|
// to write the remaining CLI output to. Use IntegrationOutputWriter.End() to complete integration
|
|
// output
|
|
func (s *IntegrationContext) BeginOutput(name string) IntegrationOutputWriter {
|
|
var result IntegrationOutputWriter = &integrationCLIOutput{
|
|
CLI: s.B.CLI,
|
|
Colorizer: s.B.Colorize(),
|
|
started: time.Now(),
|
|
}
|
|
|
|
result.Output("\n[bold]" + name + ":\n")
|
|
|
|
return result
|
|
}
|
|
|
|
// End writes the termination output for the integration
|
|
func (s *integrationCLIOutput) End() {
|
|
if s.CLI == nil {
|
|
return
|
|
}
|
|
|
|
s.CLI.Output("\n------------------------------------------------------------------------\n")
|
|
}
|
|
|
|
// Output writes a string after colorizing it using any [colorstrings](https://github.com/mitchellh/colorstring) it contains
|
|
func (s *integrationCLIOutput) Output(str string) {
|
|
if s.CLI == nil {
|
|
return
|
|
}
|
|
s.CLI.Output(s.Colorizer.Color(str))
|
|
}
|
|
|
|
// SubOutput writes a string prefixed by a "│ " after colorizing it using any [colorstrings](https://github.com/mitchellh/colorstring) it contains
|
|
func (s *integrationCLIOutput) SubOutput(str string) {
|
|
if s.CLI == nil {
|
|
return
|
|
}
|
|
s.CLI.Output(s.Colorizer.Color(fmt.Sprintf("[reset]│ %s", str)))
|
|
}
|
|
|
|
// OutputElapsed writes a string followed by the amount of time that has elapsed since calling BeginOutput.
|
|
// Example pending output; the variable spacing (50 chars) allows up to 99 tasks (two digits) in each category:
|
|
// ---------------
|
|
// 13 tasks still pending, 0 passed, 0 failed ...
|
|
// 13 tasks still pending, 0 passed, 0 failed ... (8s elapsed)
|
|
// 13 tasks still pending, 0 passed, 0 failed ... (19s elapsed)
|
|
// 13 tasks still pending, 0 passed, 0 failed ... (33s elapsed)
|
|
func (s *integrationCLIOutput) OutputElapsed(message string, maxMessage int) {
|
|
if s.CLI == nil {
|
|
return
|
|
}
|
|
elapsed := time.Since(s.started).Truncate(1 * time.Second)
|
|
s.CLI.Output(fmt.Sprintf("%-"+strconv.FormatInt(int64(maxMessage), 10)+"s", message) + s.Colorizer.Color(fmt.Sprintf("[dim](%s elapsed)", elapsed)))
|
|
}
|