github.com/tilt-dev/tilt@v0.36.0/internal/controllers/core/tiltfile/reducers.go (about) 1 package tiltfile 2 3 import ( 4 "context" 5 6 "github.com/tilt-dev/tilt/internal/store" 7 "github.com/tilt-dev/tilt/pkg/logger" 8 "github.com/tilt-dev/tilt/pkg/model" 9 ) 10 11 const TiltfileBuildSource = "tiltfile" 12 13 func HandleConfigsReloadStarted( 14 ctx context.Context, 15 state *store.EngineState, 16 event ConfigsReloadStartedAction, 17 ) { 18 ms, ok := state.TiltfileStates[event.Name] 19 if !ok { 20 return 21 } 22 23 status := model.BuildRecord{ 24 StartTime: event.StartTime, 25 Reason: event.Reason, 26 Edits: event.FilesChanged, 27 SpanID: event.SpanID, 28 } 29 ms.CurrentBuilds[TiltfileBuildSource] = status 30 state.RemoveFromTriggerQueue(event.Name) 31 } 32 33 // In the original Tilt architecture, the Tiltfile contained 34 // the whole engine state. Reloading the tiltfile re-created that 35 // state from scratch. 36 // 37 // We've moved towards a more modular architecture, but many of the tilt data 38 // models aren't modular. For example, if two Tiltfiles set UpdateSettings, 39 // it's not clear which one "wins" or how their preferences combine. 40 // 41 // In the long-term, Tiltfile settings should only take affect in objects created 42 // by that Tiltfile. (e.g., WatchSettings only affects FileWatches created by 43 // that Tiltfile.) 44 // 45 // In the medium-term, we resolve this in the EngineState in three different ways: 46 // 1. If a data structure supports merging (like the Manifest map), do a merge. 47 // 2. If merging fails (like if two Tiltfiles define the same Manifest), log an Error 48 // and try to do something reasonable. 49 // 3. If a data structure does not support merging (like UpdateSettings), only 50 // accept that data structure from the "main" tiltfile. 51 func HandleConfigsReloaded( 52 ctx context.Context, 53 state *store.EngineState, 54 event ConfigsReloadedAction, 55 ) { 56 isMainTiltfile := event.Name == model.MainTiltfileManifestName 57 58 manifests := event.Manifests 59 loadedManifestNames := map[model.ManifestName]bool{} 60 for i, m := range manifests { 61 loadedManifestNames[m.Name] = true 62 63 // Properly annotate the manifest with the source tiltfile. 64 m.SourceTiltfile = event.Name 65 manifests[i] = m 66 } 67 68 ms, ok := state.TiltfileStates[event.Name] 69 if !ok { 70 return 71 } 72 b := ms.CurrentBuilds[TiltfileBuildSource] 73 74 // Remove pending file changes that were consumed by this build. 75 for _, status := range ms.BuildStatuses { 76 status.ConsumeChangesBefore(b.StartTime) 77 } 78 79 // Track the new secrets and go back to scrub them. 80 newSecrets := model.SecretSet{} 81 for k, v := range event.Secrets { 82 _, exists := state.Secrets[k] 83 if !exists { 84 newSecrets[k] = v 85 } 86 } 87 88 // Add all secrets, even if we failed. 89 state.Secrets.AddAll(event.Secrets) 90 91 // Retroactively scrub secrets 92 state.LogStore.ScrubSecretsStartingAt(newSecrets, event.CheckpointAtExecStart) 93 94 // Add team id if it exists, even if execution failed. 95 if isMainTiltfile && (event.TeamID != "" || event.Err == nil) { 96 state.TeamID = event.TeamID 97 } 98 99 // if the ConfigsReloadedAction came from a unit test, there might not be a current build 100 if !b.Empty() { 101 b.FinishTime = event.FinishTime 102 b.Error = event.Err 103 104 if b.SpanID != "" { 105 b.WarningCount = len(state.LogStore.Warnings(b.SpanID)) 106 } 107 108 ms.AddCompletedBuild(b) 109 } 110 delete(ms.CurrentBuilds, TiltfileBuildSource) 111 if event.Err != nil { 112 // When the Tiltfile had an error, we want to differentiate between two cases: 113 // 114 // 1) You're running `tilt up` for the first time, and a local() command 115 // exited with status code 1. Partial results (like enabling features) 116 // would be helpful. 117 // 118 // 2) You're running 'tilt up' in the happy state. You edit the Tiltfile, 119 // and introduce a syntax error. You don't want partial results to wipe out 120 // your "good" state. 121 122 if isMainTiltfile { 123 // Enable any new features in the partial state. 124 if len(state.Features) == 0 { 125 state.Features = event.Features 126 } else { 127 for feature, val := range event.Features { 128 if val { 129 state.Features[feature] = val 130 } 131 } 132 } 133 } 134 return 135 } 136 137 // Make sure all the new manifests are in the EngineState. 138 for _, m := range manifests { 139 mt, ok := state.ManifestTargets[m.ManifestName()] 140 if ok && mt.Manifest.SourceTiltfile != event.Name { 141 logger.Get(ctx).Errorf("Resource defined in two tiltfiles: %s, %s", event.Name, mt.Manifest.SourceTiltfile) 142 continue 143 } 144 145 // Create a new manifest if it changed types. 146 createNew := !ok || 147 mt.Manifest.IsK8s() != m.IsK8s() || 148 mt.Manifest.IsLocal() != m.IsLocal() || 149 mt.Manifest.IsDC() != m.IsDC() 150 if createNew { 151 mt = store.NewManifestTarget(m) 152 } 153 154 configFilesThatChanged := ms.LastBuild().Edits 155 old := mt.Manifest 156 mt.Manifest = m 157 158 if model.ChangesInvalidateBuild(old, m) { 159 // Manifest has changed such that the current build is invalid; 160 // ensure we do an image build so that we apply the changes 161 ms := mt.State 162 ms.ResetBuildStatus(m) 163 ms.PendingManifestChange = event.FinishTime 164 ms.ConfigFilesThatCausedChange = configFilesThatChanged 165 } 166 state.UpsertManifestTarget(mt) 167 } 168 169 // Go through all the existing manifest targets. If they were from this 170 // Tiltfile, but were removed from the latest Tiltfile execution, delete them. 171 for _, mt := range state.Targets() { 172 m := mt.Manifest 173 174 if m.SourceTiltfile == event.Name { 175 if !loadedManifestNames[m.Name] { 176 state.RemoveManifestTarget(m.Name) 177 } 178 continue 179 } 180 } 181 182 // Global state that's only configurable from the main manifest. 183 if isMainTiltfile { 184 state.Features = event.Features 185 state.TelemetrySettings = event.TelemetrySettings 186 state.VersionSettings = event.VersionSettings 187 state.AnalyticsTiltfileOpt = event.AnalyticsTiltfileOpt 188 state.UpdateSettings = event.UpdateSettings 189 state.DockerPruneSettings = event.DockerPruneSettings 190 } 191 }