@@ -20,6 +20,7 @@ import (
20
20
"context"
21
21
"fmt"
22
22
"os"
23
+ "regexp"
23
24
"sort"
24
25
"strings"
25
26
"time"
@@ -284,6 +285,11 @@ func addObjectRowV1Beta2(prefix string, tbl *tablewriter.Table, objectTree *tree
284
285
// - The object's ready condition + counters
285
286
// - The object's up to date condition + counters
286
287
// - Condition "REASON", "SINCE", "MESSAGE"
288
+ msg := strings .Split (rowDescriptor .message , "\n " )
289
+ msg0 := ""
290
+ if len (msg ) > 1 {
291
+ msg0 = msg [0 ]
292
+ }
287
293
tbl .Append ([]string {
288
294
fmt .Sprintf ("%s%s" , gray .Sprint (prefix ), name ),
289
295
rowDescriptor .replicas ,
@@ -293,7 +299,20 @@ func addObjectRowV1Beta2(prefix string, tbl *tablewriter.Table, objectTree *tree
293
299
rowDescriptor .status ,
294
300
rowDescriptor .reason ,
295
301
rowDescriptor .age ,
296
- rowDescriptor .message })
302
+ msg0 })
303
+
304
+ for _ , m := range msg [1 :] {
305
+ tbl .Append ([]string {
306
+ fmt .Sprintf ("%s" , getMultilinePrefix (gray .Sprint (prefix ))),
307
+ "" ,
308
+ "" ,
309
+ "" ,
310
+ "" ,
311
+ "" ,
312
+ "" ,
313
+ "" ,
314
+ m })
315
+ }
297
316
298
317
// If it is required to show all the conditions for the object, add a row for each object's conditions.
299
318
if tree .IsShowConditionsObject (obj ) {
@@ -407,17 +426,36 @@ func addOtherConditionsV1Beta2(prefix string, tbl *tablewriter.Table, objectTree
407
426
}
408
427
409
428
childPrefix := getChildPrefix (prefix + childrenPipe + filler , i , len (conditions ))
410
- color , status , age , reason , message := v1Beta2ConditionInfo (condition , positivePolarity )
429
+ _ , status , age , reason , message := v1Beta2ConditionInfo (condition , positivePolarity )
430
+
431
+ msg := strings .Split (message , "\n " )
432
+ msg0 := ""
433
+ if len (msg ) > 1 {
434
+ msg0 = msg [0 ]
435
+ }
411
436
tbl .Append ([]string {
412
437
fmt .Sprintf ("%s%s" , gray .Sprint (childPrefix ), cyan .Sprint (condition .Type )),
413
438
"" ,
414
439
"" ,
415
440
"" ,
416
441
"" ,
417
- color .Sprint (status ),
418
- color .Sprint (reason ),
419
- color .Sprint (age ),
420
- color .Sprint (message )})
442
+ status ,
443
+ reason ,
444
+ age ,
445
+ msg0 })
446
+
447
+ for _ , m := range msg [1 :] {
448
+ tbl .Append ([]string {
449
+ fmt .Sprintf ("%s" , gray .Sprint (getMultilinePrefix (childPrefix ))),
450
+ "" ,
451
+ "" ,
452
+ "" ,
453
+ "" ,
454
+ "" ,
455
+ "" ,
456
+ "" ,
457
+ m })
458
+ }
421
459
}
422
460
}
423
461
@@ -466,6 +504,20 @@ func getChildPrefix(currentPrefix string, childIndex, childCount int) string {
466
504
return nextPrefix + lastElemPrefix
467
505
}
468
506
507
+ // getMultilinePrefix return the tree view prefix for a multiline condition.
508
+ func getMultilinePrefix (currentPrefix string ) string {
509
+ // All ├─ should be replaced by |, so all the existing hierarchic dependencies are carried on
510
+ if strings .HasSuffix (currentPrefix , firstElemPrefix ) {
511
+ return strings .TrimSuffix (currentPrefix , firstElemPrefix ) + pipe
512
+ }
513
+ // All └─ should be replaced by " " because we are under the last element of the tree (nothing to carry on)
514
+ if strings .HasSuffix (currentPrefix , lastElemPrefix ) {
515
+ return strings .TrimSuffix (currentPrefix , lastElemPrefix )
516
+ }
517
+
518
+ return "?"
519
+ }
520
+
469
521
// getRowName returns the object name in the tree view according to following rules:
470
522
// - group objects are represented as #of objects kind, e.g. 3 Machines...
471
523
// - other virtual objects are represented using the object name, e.g. Workers, or meta name if provided.
@@ -544,11 +596,11 @@ func newV1beta2RowDescriptor(obj ctrlclient.Object) v1beta2RowDescriptor {
544
596
}
545
597
546
598
if available := tree .GetAvailableV1Beta2Condition (obj ); available != nil {
547
- availableColor , availableStatus , availableAge , availableReason , availableMessage := v1Beta2ConditionInfo (* available , true )
548
- v .status = availableColor .Sprintf ("Available: %s" , availableStatus )
549
- v .reason = availableColor . Sprint ( availableReason )
550
- v .age = availableColor . Sprint ( availableAge )
551
- v .message = availableColor . Sprint ( availableMessage )
599
+ _ , availableStatus , availableAge , availableReason , availableMessage := v1Beta2ConditionInfo (* available , true )
600
+ v .status = fmt .Sprintf ("Available: %s" , availableStatus )
601
+ v .reason = availableReason
602
+ v .age = availableAge
603
+ v .message = availableMessage
552
604
}
553
605
case * clusterv1.MachineDeployment :
554
606
md := obj .(* clusterv1.MachineDeployment )
@@ -604,11 +656,11 @@ func newV1beta2RowDescriptor(obj ctrlclient.Object) v1beta2RowDescriptor {
604
656
605
657
v .readyCounters = "0"
606
658
if ready := tree .GetReadyV1Beta2Condition (obj ); ready != nil {
607
- readyColor , readyStatus , readyAge , readyReason , readyMessage := v1Beta2ConditionInfo (* ready , true )
608
- v .status = readyColor .Sprintf ("Ready: %s" , readyStatus )
609
- v .reason = readyColor . Sprint ( readyReason )
610
- v .age = readyColor . Sprint ( readyAge )
611
- v .message = readyColor . Sprint ( readyMessage )
659
+ _ , readyStatus , readyAge , readyReason , readyMessage := v1Beta2ConditionInfo (* ready , true )
660
+ v .status = fmt .Sprintf ("Ready: %s" , readyStatus )
661
+ v .reason = readyReason
662
+ v .age = readyAge
663
+ v .message = readyMessage
612
664
if ready .Status == metav1 .ConditionTrue {
613
665
v .readyCounters = "1"
614
666
}
@@ -623,8 +675,8 @@ func newV1beta2RowDescriptor(obj ctrlclient.Object) v1beta2RowDescriptor {
623
675
624
676
case * unstructured.Unstructured :
625
677
if ready := tree .GetReadyV1Beta2Condition (obj ); ready != nil {
626
- readyColor , readyStatus , readyAge , readyReason , readyMessage := v1Beta2ConditionInfo (* ready , true )
627
- v .status = readyColor .Sprintf ("Ready: %s" , readyStatus )
678
+ _ , readyStatus , readyAge , readyReason , readyMessage := v1Beta2ConditionInfo (* ready , true )
679
+ v .status = fmt .Sprintf ("Ready: %s" , readyStatus )
628
680
v .reason = readyReason
629
681
v .age = readyAge
630
682
v .message = readyMessage
@@ -686,15 +738,40 @@ func v1Beta2ConditionInfo(c metav1.Condition, positivePolarity bool) (color *col
686
738
status = string (c .Status )
687
739
reason = c .Reason
688
740
age = duration .HumanDuration (time .Since (c .LastTransitionTime .Time ))
689
- message = c .Message
741
+ message = formatParagraph ( c .Message , 100 )
690
742
691
- // Eventually cut the message to keep the table dimension under control.
692
- if len (message ) > 100 {
693
- message = fmt .Sprintf ("%s ..." , message [:100 ])
694
- }
695
743
return
696
744
}
697
745
746
+ var re = regexp .MustCompile ("[\\ s]+" )
747
+
748
+ func formatParagraph (text string , maxWidth int ) string {
749
+ lines := []string {}
750
+ for _ , l := range strings .Split (text , "\n " ) {
751
+ tmp := ""
752
+ for _ , c := range []rune (l ) {
753
+ if c == ' ' {
754
+ tmp += " "
755
+ continue
756
+ }
757
+ break
758
+ }
759
+ for _ , w := range re .Split (l , - 1 ) {
760
+ if len (tmp )+ len (w ) < maxWidth {
761
+ if strings .TrimSpace (tmp ) != "" {
762
+ tmp += " "
763
+ }
764
+ tmp += w
765
+ continue
766
+ }
767
+ lines = append (lines , tmp )
768
+ tmp = w
769
+ }
770
+ lines = append (lines , tmp )
771
+ }
772
+ return strings .Join (lines , "\n " )
773
+ }
774
+
698
775
// conditionDescriptor contains all the info for representing a condition.
699
776
type conditionDescriptor struct {
700
777
readyColor * color.Color
0 commit comments