github.com/tilt-dev/tilt@v0.36.0/internal/hud/view.go (about) 1 package hud 2 3 import ( 4 "os" 5 "sort" 6 "sync" 7 8 "github.com/tilt-dev/tilt/internal/dockercompose" 9 "github.com/tilt-dev/tilt/internal/hud/view" 10 "github.com/tilt-dev/tilt/internal/k8s" 11 "github.com/tilt-dev/tilt/internal/ospath" 12 "github.com/tilt-dev/tilt/internal/store" 13 "github.com/tilt-dev/tilt/internal/store/k8sconv" 14 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 15 "github.com/tilt-dev/tilt/pkg/model" 16 "github.com/tilt-dev/tilt/pkg/model/logstore" 17 ) 18 19 func StateToTerminalView(s store.EngineState, mu *sync.RWMutex) view.View { 20 ret := view.View{} 21 22 for _, ms := range s.TiltfileStates { 23 ret.Resources = append(ret.Resources, tiltfileResourceView(ms)) 24 } 25 26 for _, name := range s.ManifestDefinitionOrder { 27 mt, ok := s.ManifestTargets[name] 28 if !ok { 29 continue 30 } 31 32 ms := mt.State 33 if ms.DisableState == v1alpha1.DisableStateDisabled { 34 // Don't show disabled resources in the terminal UI. 35 continue 36 } 37 38 var absWatchDirs []string 39 for i, p := range mt.Manifest.LocalPaths() { 40 if i > 50 { 41 // Bail out after 50 to avoid pathological performance issues. 42 break 43 } 44 fi, err := os.Stat(p) 45 46 // Treat this as a directory when there's an error. 47 if err != nil || fi.IsDir() { 48 absWatchDirs = append(absWatchDirs, p) 49 } 50 } 51 52 var pendingBuildEdits []string 53 for _, status := range ms.BuildStatuses { 54 pendingBuildEdits = append(pendingBuildEdits, status.PendingFileChangesList()...) 55 } 56 57 pendingBuildEdits = ospath.FileListDisplayNames(absWatchDirs, pendingBuildEdits) 58 59 buildHistory := append([]model.BuildRecord{}, ms.BuildHistory...) 60 for i, build := range buildHistory { 61 build.Edits = ospath.FileListDisplayNames(absWatchDirs, build.Edits) 62 buildHistory[i] = build 63 } 64 65 currentBuild := ms.EarliestCurrentBuild() 66 currentBuild.Edits = ospath.FileListDisplayNames(absWatchDirs, currentBuild.Edits) 67 68 // Sort the strings to make the outputs deterministic. 69 sort.Strings(pendingBuildEdits) 70 71 endpoints := store.ManifestTargetEndpoints(mt) 72 73 // NOTE(nick): Right now, the UX is designed to show the output exactly one 74 // pod. A better UI might summarize the pods in other ways (e.g., show the 75 // "most interesting" pod that's crash looping, or show logs from all pods 76 // at once). 77 _, pendingBuildSince := ms.HasPendingChanges() 78 r := view.Resource{ 79 Name: name, 80 LastDeployTime: ms.LastSuccessfulDeployTime, 81 TriggerMode: mt.Manifest.TriggerMode, 82 BuildHistory: buildHistory, 83 PendingBuildEdits: pendingBuildEdits, 84 PendingBuildSince: pendingBuildSince, 85 PendingBuildReason: mt.NextBuildReason(), 86 CurrentBuild: currentBuild, 87 Endpoints: model.LinksToURLStrings(endpoints), // hud can't handle link names, just send URLs 88 ResourceInfo: resourceInfoView(mt), 89 } 90 91 ret.Resources = append(ret.Resources, r) 92 } 93 94 ret.LogReader = logstore.NewReader(mu, s.LogStore) 95 ret.FatalError = s.FatalError 96 97 return ret 98 } 99 100 const MainTiltfileManifestName = model.MainTiltfileManifestName 101 102 func tiltfileResourceView(ms *store.ManifestState) view.Resource { 103 currentBuild := ms.EarliestCurrentBuild() 104 tr := view.Resource{ 105 Name: MainTiltfileManifestName, 106 IsTiltfile: true, 107 CurrentBuild: currentBuild, 108 BuildHistory: ms.BuildHistory, 109 ResourceInfo: view.TiltfileResourceInfo{}, 110 } 111 if !currentBuild.Empty() { 112 tr.PendingBuildSince = currentBuild.StartTime 113 } else { 114 tr.LastDeployTime = ms.LastBuild().FinishTime 115 } 116 return tr 117 } 118 119 func resourceInfoView(mt *store.ManifestTarget) view.ResourceInfoView { 120 runStatus := mt.RuntimeStatus() 121 switch state := mt.State.RuntimeState.(type) { 122 case dockercompose.State: 123 return view.NewDCResourceInfo( 124 state.ContainerState.Status, state.ContainerID, state.SpanID, state.ContainerState.StartedAt.Time, runStatus) 125 case store.K8sRuntimeState: 126 if mt.Manifest.PodReadinessMode() == model.PodReadinessIgnore { 127 return view.YAMLResourceInfo{ 128 K8sDisplayNames: state.EntityDisplayNames(), 129 } 130 } 131 pod := state.MostRecentPod() 132 podID := k8s.PodID(pod.Name) 133 return view.K8sResourceInfo{ 134 PodName: pod.Name, 135 PodCreationTime: pod.CreatedAt.Time, 136 PodUpdateStartTime: state.UpdateStartTime[podID], 137 PodStatus: pod.Status, 138 PodRestarts: int(state.VisiblePodContainerRestarts(podID)), 139 SpanID: k8sconv.SpanIDForPod(mt.Manifest.Name, podID), 140 RunStatus: runStatus, 141 DisplayNames: state.EntityDisplayNames(), 142 } 143 case store.LocalRuntimeState: 144 return view.NewLocalResourceInfo(runStatus, state.PID, state.SpanID) 145 default: 146 // This is silly but it was the old behavior. 147 return view.K8sResourceInfo{} 148 } 149 }