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  }