github.com/grahambrereton-form3/tilt@v0.10.18/internal/engine/build_and_deployer.go (about) 1 package engine 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/windmilleng/tilt/internal/container" 9 "github.com/windmilleng/tilt/internal/k8s" 10 "github.com/windmilleng/tilt/internal/store" 11 12 "github.com/windmilleng/tilt/pkg/logger" 13 "github.com/windmilleng/tilt/pkg/model" 14 ) 15 16 type BuildAndDeployer interface { 17 // BuildAndDeploy builds and deployed the specified target specs. 18 // 19 // Returns a BuildResult that expresses the outputs(s) of the build. 20 // 21 // BuildResult can be used to construct a set of BuildStates, which contain 22 // the last successful builds of each target and the files changed since that build. 23 BuildAndDeploy(ctx context.Context, st store.RStore, specs []model.TargetSpec, currentState store.BuildStateSet) (store.BuildResultSet, error) 24 } 25 26 type BuildOrder []BuildAndDeployer 27 28 func (bo BuildOrder) String() string { 29 var output strings.Builder 30 output.WriteString("BuildOrder{") 31 32 for _, b := range bo { 33 output.WriteString(fmt.Sprintf(" %T", b)) 34 } 35 36 output.WriteString(" }") 37 38 return output.String() 39 } 40 41 type FallbackTester func(error) bool 42 43 // CompositeBuildAndDeployer tries to run each builder in order. If a builder 44 // emits an error, it uses the FallbackTester to determine whether the error is 45 // critical enough to stop the whole pipeline, or to fallback to the next 46 // builder. 47 type CompositeBuildAndDeployer struct { 48 builders BuildOrder 49 } 50 51 var _ BuildAndDeployer = &CompositeBuildAndDeployer{} 52 53 func NewCompositeBuildAndDeployer(builders BuildOrder) *CompositeBuildAndDeployer { 54 return &CompositeBuildAndDeployer{builders: builders} 55 } 56 57 func (composite *CompositeBuildAndDeployer) BuildAndDeploy(ctx context.Context, st store.RStore, specs []model.TargetSpec, currentState store.BuildStateSet) (store.BuildResultSet, error) { 58 var lastErr, lastUnexpectedErr error 59 logger.Get(ctx).Debugf("Building with BuildOrder: %s", composite.builders.String()) 60 for i, builder := range composite.builders { 61 logger.Get(ctx).Debugf("Trying to build and deploy with %T", builder) 62 br, err := builder.BuildAndDeploy(ctx, st, specs, currentState) 63 if err == nil { 64 return br, err 65 } 66 67 if !shouldFallBackForErr(err) { 68 return br, err 69 } 70 71 if redirectErr, ok := err.(RedirectToNextBuilder); ok { 72 s := fmt.Sprintf("falling back to next update method because: %v\n", err) 73 logger.Get(ctx).Write(redirectErr.level, s) 74 } else { 75 lastUnexpectedErr = err 76 if i+1 < len(composite.builders) { 77 logger.Get(ctx).Infof("got unexpected error during build/deploy: %v", err) 78 } 79 } 80 lastErr = err 81 } 82 83 if lastUnexpectedErr != nil { 84 // The most interesting error is the last UNEXPECTED error we got 85 return store.BuildResultSet{}, lastUnexpectedErr 86 } 87 return store.BuildResultSet{}, lastErr 88 } 89 90 func DefaultBuildOrder(lubad *LiveUpdateBuildAndDeployer, ibad *ImageBuildAndDeployer, dcbad *DockerComposeBuildAndDeployer, 91 ltbad *LocalTargetBuildAndDeployer, updMode UpdateMode, env k8s.Env, runtime container.Runtime) BuildOrder { 92 if updMode == UpdateModeImage || updMode == UpdateModeNaive { 93 return BuildOrder{dcbad, ibad, ltbad} 94 } 95 96 if updMode == UpdateModeSynclet || shouldUseSynclet(updMode, env, runtime) { 97 ibad.SetInjectSynclet(true) 98 } 99 100 return BuildOrder{lubad, dcbad, ibad, ltbad} 101 } 102 103 func shouldUseSynclet(updMode UpdateMode, env k8s.Env, runtime container.Runtime) bool { 104 return updMode == UpdateModeAuto && !env.UsesLocalDockerRegistry() && runtime == container.RuntimeDocker 105 }