github.com/grahambrereton-form3/tilt@v0.10.18/internal/hud/view/view.go (about)

     1  package view
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/windmilleng/tilt/internal/container"
     7  	"github.com/windmilleng/tilt/internal/dockercompose"
     8  	"github.com/windmilleng/tilt/pkg/model"
     9  )
    10  
    11  const TiltfileResourceName = "(Tiltfile)"
    12  
    13  type ResourceInfoView interface {
    14  	resourceInfoView()
    15  	RuntimeLog() model.Log
    16  	Status() string
    17  }
    18  
    19  type DCResourceInfo struct {
    20  	ConfigPaths     []string
    21  	ContainerStatus dockercompose.Status
    22  	ContainerID     container.ID
    23  	Log             model.Log
    24  	StartTime       time.Time
    25  }
    26  
    27  func NewDCResourceInfo(configPaths []string, status dockercompose.Status, cID container.ID, log model.Log, startTime time.Time) DCResourceInfo {
    28  	return DCResourceInfo{
    29  		ConfigPaths:     configPaths,
    30  		ContainerStatus: status,
    31  		ContainerID:     cID,
    32  		Log:             log,
    33  		StartTime:       startTime,
    34  	}
    35  }
    36  
    37  var _ ResourceInfoView = DCResourceInfo{}
    38  
    39  func (DCResourceInfo) resourceInfoView()            {}
    40  func (dcInfo DCResourceInfo) RuntimeLog() model.Log { return dcInfo.Log }
    41  func (dcInfo DCResourceInfo) Status() string        { return string(dcInfo.ContainerStatus) }
    42  
    43  type K8sResourceInfo struct {
    44  	PodName            string
    45  	PodCreationTime    time.Time
    46  	PodUpdateStartTime time.Time
    47  	PodStatus          string
    48  	PodRestarts        int
    49  	PodLog             model.Log
    50  }
    51  
    52  var _ ResourceInfoView = K8sResourceInfo{}
    53  
    54  func (K8sResourceInfo) resourceInfoView()             {}
    55  func (k8sInfo K8sResourceInfo) RuntimeLog() model.Log { return k8sInfo.PodLog }
    56  func (k8sInfo K8sResourceInfo) Status() string        { return k8sInfo.PodStatus }
    57  
    58  type YAMLResourceInfo struct {
    59  	K8sResources []string
    60  }
    61  
    62  var _ ResourceInfoView = YAMLResourceInfo{}
    63  
    64  func (YAMLResourceInfo) resourceInfoView()              {}
    65  func (yamlInfo YAMLResourceInfo) RuntimeLog() model.Log { return model.NewLog("") }
    66  func (yamlInfo YAMLResourceInfo) Status() string        { return "" }
    67  
    68  type LocalResourceInfo struct {
    69  }
    70  
    71  var _ ResourceInfoView = LocalResourceInfo{}
    72  
    73  var LocalResourceStatusPlaceholder = "local-resource-ok"
    74  
    75  func (LocalResourceInfo) resourceInfoView()     {}
    76  func (LocalResourceInfo) RuntimeLog() model.Log { return model.Log{} }                    // no runtime log, only build log
    77  func (LocalResourceInfo) Status() string        { return LocalResourceStatusPlaceholder } // no status independent of build status
    78  
    79  type Resource struct {
    80  	Name               model.ManifestName
    81  	DirectoriesWatched []string
    82  	PathsWatched       []string
    83  	LastDeployTime     time.Time
    84  	TriggerMode        model.TriggerMode
    85  
    86  	BuildHistory []model.BuildRecord
    87  	CurrentBuild model.BuildRecord
    88  
    89  	PendingBuildReason model.BuildReason
    90  	PendingBuildEdits  []string
    91  	PendingBuildSince  time.Time
    92  
    93  	Endpoints []string
    94  
    95  	ResourceInfo ResourceInfoView
    96  
    97  	// If a pod had to be killed because it was crashing, we keep the old log around
    98  	// for a little while.
    99  	CrashLog model.Log
   100  
   101  	IsTiltfile bool
   102  }
   103  
   104  func (r Resource) DockerComposeTarget() DCResourceInfo {
   105  	switch info := r.ResourceInfo.(type) {
   106  	case DCResourceInfo:
   107  		return info
   108  	default:
   109  		return DCResourceInfo{}
   110  	}
   111  }
   112  
   113  func (r Resource) DCInfo() DCResourceInfo {
   114  	ret, _ := r.ResourceInfo.(DCResourceInfo)
   115  	return ret
   116  }
   117  
   118  func (r Resource) IsDC() bool {
   119  	_, ok := r.ResourceInfo.(DCResourceInfo)
   120  	return ok
   121  }
   122  
   123  func (r Resource) K8sInfo() K8sResourceInfo {
   124  	ret, _ := r.ResourceInfo.(K8sResourceInfo)
   125  	return ret
   126  }
   127  
   128  func (r Resource) IsK8s() bool {
   129  	_, ok := r.ResourceInfo.(K8sResourceInfo)
   130  	return ok
   131  }
   132  
   133  func (r Resource) YAMLInfo() YAMLResourceInfo {
   134  	ret, _ := r.ResourceInfo.(YAMLResourceInfo)
   135  	return ret
   136  }
   137  
   138  func (r Resource) IsYAML() bool {
   139  	_, ok := r.ResourceInfo.(YAMLResourceInfo)
   140  	return ok
   141  }
   142  
   143  func (r Resource) LastBuild() model.BuildRecord {
   144  	if len(r.BuildHistory) == 0 {
   145  		return model.BuildRecord{}
   146  	}
   147  	return r.BuildHistory[0]
   148  }
   149  
   150  func (r Resource) DefaultCollapse() bool {
   151  	autoExpand := false
   152  	if k8sInfo, ok := r.ResourceInfo.(K8sResourceInfo); ok {
   153  		autoExpand = k8sInfo.PodRestarts > 0 || k8sInfo.PodStatus == "CrashLoopBackOff" || k8sInfo.PodStatus == "Error"
   154  	}
   155  
   156  	if r.IsYAML() {
   157  		autoExpand = true
   158  	}
   159  
   160  	if r.IsDC() && r.DockerComposeTarget().Status() == string(dockercompose.StatusCrash) {
   161  		autoExpand = true
   162  	}
   163  
   164  	autoExpand = autoExpand ||
   165  		r.LastBuild().Error != nil ||
   166  		!r.CrashLog.Empty() ||
   167  		len(r.LastBuild().Warnings) > 0 ||
   168  		r.LastBuild().Reason.Has(model.BuildReasonFlagCrash) ||
   169  		r.CurrentBuild.Reason.Has(model.BuildReasonFlagCrash) ||
   170  		r.PendingBuildReason.Has(model.BuildReasonFlagCrash)
   171  	return !autoExpand
   172  }
   173  
   174  func (r Resource) IsCollapsed(rv ResourceViewState) bool {
   175  	return rv.CollapseState.IsCollapsed(r.DefaultCollapse())
   176  }
   177  
   178  // Snapshot of the current view that's not expressed in the underlying model state.
   179  //
   180  // This includes things like the current selection, warning messages,
   181  // narration messages, etc.
   182  //
   183  // Client should always hold this as a value struct, and copy it
   184  // whenever they need to mutate something.
   185  type View struct {
   186  	Log           model.Log
   187  	Resources     []Resource
   188  	IsProfiling   bool
   189  	LogTimestamps bool
   190  	FatalError    error
   191  }
   192  
   193  func (v View) TiltfileErrorMessage() string {
   194  	for _, res := range v.Resources {
   195  		if res.Name == TiltfileResourceName {
   196  			err := res.LastBuild().Error
   197  			if err != nil {
   198  				return err.Error()
   199  			}
   200  			return ""
   201  		}
   202  	}
   203  	return ""
   204  }
   205  
   206  func (v View) Resource(n model.ManifestName) (Resource, bool) {
   207  	for _, res := range v.Resources {
   208  		if res.Name == n {
   209  			return res, true
   210  		}
   211  	}
   212  	return Resource{}, false
   213  }
   214  
   215  type ViewState struct {
   216  	ShowNarration         bool
   217  	NarrationMessage      string
   218  	Resources             []ResourceViewState
   219  	ProcessedLogByteCount int
   220  	AlertMessage          string
   221  	TabState              TabState
   222  	SelectedIndex         int
   223  	TiltLogState          TiltLogState
   224  }
   225  
   226  type TabState int
   227  
   228  const (
   229  	TabAllLog TabState = iota
   230  	TabBuildLog
   231  	TabPodLog
   232  )
   233  
   234  type CollapseState int
   235  
   236  const (
   237  	CollapseAuto = iota
   238  	CollapseYes
   239  	CollapseNo
   240  )
   241  
   242  func (c CollapseState) IsCollapsed(defaultCollapse bool) bool {
   243  	switch c {
   244  	case CollapseYes:
   245  		return true
   246  	case CollapseNo:
   247  		return false
   248  	default: // CollapseAuto
   249  		return defaultCollapse
   250  	}
   251  }
   252  
   253  func (vs *ViewState) CycleViewLogState() {
   254  	states := []TiltLogState{TiltLogShort, TiltLogHalfScreen, TiltLogFullScreen}
   255  	for i := range states {
   256  		if states[i] == vs.TiltLogState {
   257  			vs.TiltLogState = states[(i+1)%len(states)]
   258  			return
   259  		}
   260  	}
   261  	vs.TiltLogState = TiltLogFullScreen
   262  }
   263  
   264  type TiltLogState int
   265  
   266  const (
   267  	TiltLogShort TiltLogState = iota
   268  	TiltLogHalfScreen
   269  	TiltLogFullScreen
   270  )
   271  
   272  type ResourceViewState struct {
   273  	CollapseState CollapseState
   274  }