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 }