github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/tree.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"text/tabwriter"
     7  	"time"
     8  
     9  	"github.com/argoproj/gitops-engine/pkg/health"
    10  	"k8s.io/apimachinery/pkg/util/duration"
    11  
    12  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    13  )
    14  
    15  const (
    16  	firstElemPrefix = `├─`
    17  	lastElemPrefix  = `└─`
    18  	indent          = "  "
    19  	pipe            = `│ `
    20  )
    21  
    22  func extractHealthStatusAndReason(node v1alpha1.ResourceNode) (healthStatus health.HealthStatusCode, reason string) {
    23  	if node.Health != nil {
    24  		healthStatus = node.Health.Status
    25  		reason = node.Health.Message
    26  	}
    27  	return
    28  }
    29  
    30  func treeViewAppGet(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentToChildMap map[string][]string, parent v1alpha1.ResourceNode, mapNodeNameToResourceState map[string]*resourceState, w *tabwriter.Writer) {
    31  	healthStatus, _ := extractHealthStatusAndReason(parent)
    32  	if mapNodeNameToResourceState[parent.Kind+"/"+parent.Name] != nil {
    33  		value := mapNodeNameToResourceState[parent.Kind+"/"+parent.Name]
    34  		_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+value.Name, value.Status, value.Health, value.Message)
    35  	} else {
    36  		_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+parent.Name, "", healthStatus, "")
    37  	}
    38  	chs := parentToChildMap[parent.UID]
    39  	for i, childUID := range chs {
    40  		var p string
    41  		switch i {
    42  		case len(chs) - 1:
    43  			p = prefix + lastElemPrefix
    44  		default:
    45  			p = prefix + firstElemPrefix
    46  		}
    47  		treeViewAppGet(p, uidToNodeMap, parentToChildMap, uidToNodeMap[childUID], mapNodeNameToResourceState, w)
    48  	}
    49  }
    50  
    51  func detailedTreeViewAppGet(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, mapNodeNameToResourceState map[string]*resourceState, w *tabwriter.Writer) {
    52  	healthStatus, reason := extractHealthStatusAndReason(parent)
    53  	age := "<unknown>"
    54  	if parent.CreatedAt != nil {
    55  		age = duration.HumanDuration(time.Since(parent.CreatedAt.Time))
    56  	}
    57  
    58  	if mapNodeNameToResourceState[parent.Kind+"/"+parent.Name] != nil {
    59  		value := mapNodeNameToResourceState[parent.Kind+"/"+parent.Name]
    60  		_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+value.Name, value.Status, value.Health, age, value.Message, reason)
    61  	} else {
    62  		_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+parent.Name, "", healthStatus, age, "", reason)
    63  	}
    64  	chs := parentChildMap[parent.UID]
    65  	for i, child := range chs {
    66  		var p string
    67  		switch i {
    68  		case len(chs) - 1:
    69  			p = prefix + lastElemPrefix
    70  		default:
    71  			p = prefix + firstElemPrefix
    72  		}
    73  		detailedTreeViewAppGet(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], mapNodeNameToResourceState, w)
    74  	}
    75  }
    76  
    77  func treeViewAppResourcesNotOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) {
    78  	if len(parent.ParentRefs) == 0 {
    79  		_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "No")
    80  	}
    81  	chs := parentChildMap[parent.UID]
    82  	for i, child := range chs {
    83  		var p string
    84  		switch i {
    85  		case len(chs) - 1:
    86  			p = prefix + lastElemPrefix
    87  		default:
    88  			p = prefix + firstElemPrefix
    89  		}
    90  		treeViewAppResourcesNotOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w)
    91  	}
    92  }
    93  
    94  func treeViewAppResourcesOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) {
    95  	_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "Yes")
    96  	chs := parentChildMap[parent.UID]
    97  	for i, child := range chs {
    98  		var p string
    99  		switch i {
   100  		case len(chs) - 1:
   101  			p = prefix + lastElemPrefix
   102  		default:
   103  			p = prefix + firstElemPrefix
   104  		}
   105  		treeViewAppResourcesOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w)
   106  	}
   107  }
   108  
   109  func detailedTreeViewAppResourcesNotOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) {
   110  	if len(parent.ParentRefs) == 0 {
   111  		healthStatus, reason := extractHealthStatusAndReason(parent)
   112  		age := "<unknown>"
   113  		if parent.CreatedAt != nil {
   114  			age = duration.HumanDuration(time.Since(parent.CreatedAt.Time))
   115  		}
   116  		_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "No", age, healthStatus, reason)
   117  	}
   118  	chs := parentChildMap[parent.UID]
   119  	for i, child := range chs {
   120  		var p string
   121  		switch i {
   122  		case len(chs) - 1:
   123  			p = prefix + lastElemPrefix
   124  		default:
   125  			p = prefix + firstElemPrefix
   126  		}
   127  		detailedTreeViewAppResourcesNotOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w)
   128  	}
   129  }
   130  
   131  func detailedTreeViewAppResourcesOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) {
   132  	healthStatus, reason := extractHealthStatusAndReason(parent)
   133  	age := "<unknown>"
   134  	if parent.CreatedAt != nil {
   135  		age = duration.HumanDuration(time.Since(parent.CreatedAt.Time))
   136  	}
   137  	_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "Yes", age, healthStatus, reason)
   138  
   139  	chs := parentChildMap[parent.UID]
   140  	for i, child := range chs {
   141  		var p string
   142  		switch i {
   143  		case len(chs) - 1:
   144  			p = prefix + lastElemPrefix
   145  		default:
   146  			p = prefix + firstElemPrefix
   147  		}
   148  		detailedTreeViewAppResourcesOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w)
   149  	}
   150  }
   151  
   152  func printPrefix(p string) string {
   153  	if strings.HasSuffix(p, firstElemPrefix) {
   154  		p = strings.Replace(p, firstElemPrefix, pipe, strings.Count(p, firstElemPrefix)-1)
   155  	} else {
   156  		p = strings.ReplaceAll(p, firstElemPrefix, pipe)
   157  	}
   158  
   159  	if strings.HasSuffix(p, lastElemPrefix) {
   160  		p = strings.Replace(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix))), strings.Count(p, lastElemPrefix)-1)
   161  	} else {
   162  		p = strings.ReplaceAll(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix))))
   163  	}
   164  	return p
   165  }