github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/engine/build_and_deployer.go (about)

     1  package engine
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"go.opentelemetry.io/otel/attribute"
     9  	"go.opentelemetry.io/otel/trace"
    10  
    11  	"github.com/tilt-dev/tilt/internal/engine/buildcontrol"
    12  	"github.com/tilt-dev/tilt/internal/store"
    13  	"github.com/tilt-dev/tilt/internal/store/liveupdates"
    14  	"github.com/tilt-dev/tilt/pkg/logger"
    15  	"github.com/tilt-dev/tilt/pkg/model"
    16  )
    17  
    18  type BuildOrder []buildcontrol.BuildAndDeployer
    19  
    20  func (bo BuildOrder) String() string {
    21  	var output strings.Builder
    22  	output.WriteString("BuildOrder{")
    23  
    24  	for _, b := range bo {
    25  		output.WriteString(fmt.Sprintf(" %T", b))
    26  	}
    27  
    28  	output.WriteString(" }")
    29  
    30  	return output.String()
    31  }
    32  
    33  type FallbackTester func(error) bool
    34  
    35  // CompositeBuildAndDeployer tries to run each builder in order.  If a builder
    36  // emits an error, it uses the FallbackTester to determine whether the error is
    37  // critical enough to stop the whole pipeline, or to fallback to the next
    38  // builder.
    39  type CompositeBuildAndDeployer struct {
    40  	builders BuildOrder
    41  	tracer   trace.Tracer
    42  }
    43  
    44  var _ buildcontrol.BuildAndDeployer = &CompositeBuildAndDeployer{}
    45  
    46  func NewCompositeBuildAndDeployer(builders BuildOrder, tracer trace.Tracer) *CompositeBuildAndDeployer {
    47  	return &CompositeBuildAndDeployer{builders: builders, tracer: tracer}
    48  }
    49  
    50  func (composite *CompositeBuildAndDeployer) BuildAndDeploy(ctx context.Context, st store.RStore, specs []model.TargetSpec, currentState store.BuildStateSet) (store.BuildResultSet, error) {
    51  	ctx, span := composite.tracer.Start(ctx, "update")
    52  	defer span.End()
    53  	var lastErr, lastUnexpectedErr error
    54  
    55  	specNames := []string{}
    56  
    57  	for _, s := range specs {
    58  		specNames = append(specNames, s.ID().String())
    59  	}
    60  	span.SetAttributes(attribute.KeyValue{Key: attribute.Key("targetNames"), Value: attribute.StringValue(strings.Join(specNames, ","))})
    61  
    62  	logger.Get(ctx).Debugf("Building with BuildOrder: %s", composite.builders.String())
    63  	for i, builder := range composite.builders {
    64  		buildType := fmt.Sprintf("%T", builder)
    65  		logger.Get(ctx).Debugf("Trying to build and deploy with %s", buildType)
    66  
    67  		br, err := builder.BuildAndDeploy(ctx, st, specs, currentState)
    68  		if err == nil {
    69  			buildTypes := br.BuildTypes()
    70  			for _, bt := range buildTypes {
    71  				span.SetAttributes(attribute.KeyValue{Key: attribute.Key(fmt.Sprintf("buildType.%s", bt)), Value: attribute.BoolValue(true)})
    72  			}
    73  			return br, nil
    74  		}
    75  
    76  		if !buildcontrol.ShouldFallBackForErr(err) {
    77  			return br, err
    78  		}
    79  
    80  		l := logger.Get(ctx).WithFields(logger.Fields{logger.FieldNameBuildEvent: "fallback"})
    81  
    82  		if redirectErr, ok := err.(buildcontrol.RedirectToNextBuilder); ok {
    83  			s := fmt.Sprintf("Falling back to next update method…\nREASON: %v\n", err)
    84  			l.Write(redirectErr.Level, []byte(s))
    85  		} else {
    86  			lastUnexpectedErr = err
    87  			if i+1 < len(composite.builders) {
    88  				logger.Get(ctx).Infof("got unexpected error during build/deploy: %v", err)
    89  			}
    90  		}
    91  		lastErr = err
    92  	}
    93  
    94  	if lastUnexpectedErr != nil {
    95  		// The most interesting error is the last UNEXPECTED error we got
    96  		return store.BuildResultSet{}, lastUnexpectedErr
    97  	}
    98  	return store.BuildResultSet{}, lastErr
    99  }
   100  
   101  func DefaultBuildOrder(ibad *buildcontrol.ImageBuildAndDeployer, dcbad *buildcontrol.DockerComposeBuildAndDeployer,
   102  	ltbad *buildcontrol.LocalTargetBuildAndDeployer, updMode liveupdates.UpdateMode) BuildOrder {
   103  	if updMode == liveupdates.UpdateModeImage {
   104  		return BuildOrder{dcbad, ibad, ltbad}
   105  	}
   106  
   107  	return BuildOrder{dcbad, ibad, ltbad}
   108  }