istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/util/util.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package util
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"os"
    21  	"path/filepath"
    22  	"strconv"
    23  	"strings"
    24  	"text/template"
    25  
    26  	"google.golang.org/protobuf/types/known/structpb"
    27  )
    28  
    29  type FileFilter func(fileName string) bool
    30  
    31  // StringBoolMapToSlice creates and returns a slice of all the map keys with true.
    32  func StringBoolMapToSlice(m map[string]bool) []string {
    33  	s := make([]string, 0, len(m))
    34  	for k, v := range m {
    35  		if v {
    36  			s = append(s, k)
    37  		}
    38  	}
    39  	return s
    40  }
    41  
    42  // ReadFilesWithFilter reads files from path, for a directory it recursively reads files and filters the results
    43  // for single file it directly reads the file. It returns a concatenated output of all matching files' content.
    44  func ReadFilesWithFilter(path string, filter FileFilter) (string, error) {
    45  	fileList, err := FindFiles(path, filter)
    46  	if err != nil {
    47  		return "", err
    48  	}
    49  	var sb strings.Builder
    50  	for _, file := range fileList {
    51  		a, err := os.ReadFile(file)
    52  		if err != nil {
    53  			return "", err
    54  		}
    55  		if _, err := sb.WriteString(string(a) + "\n"); err != nil {
    56  			return "", err
    57  		}
    58  	}
    59  	return sb.String(), nil
    60  }
    61  
    62  // FindFiles reads files from path, and returns the file names that match the filter.
    63  func FindFiles(path string, filter FileFilter) ([]string, error) {
    64  	fi, err := os.Stat(path)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	var fileList []string
    69  	if fi.IsDir() {
    70  		err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
    71  			if err != nil {
    72  				return err
    73  			}
    74  			if info.IsDir() || !filter(path) {
    75  				return nil
    76  			}
    77  			fileList = append(fileList, path)
    78  			return nil
    79  		})
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  	} else {
    84  		fileList = append(fileList, path)
    85  	}
    86  	return fileList, nil
    87  }
    88  
    89  // ParseValue parses string into a value
    90  func ParseValue(valueStr string) any {
    91  	var value any
    92  	if v, err := strconv.Atoi(valueStr); err == nil {
    93  		value = v
    94  	} else if v, err := strconv.ParseFloat(valueStr, 64); err == nil {
    95  		value = v
    96  	} else if v, err := strconv.ParseBool(valueStr); err == nil {
    97  		value = v
    98  	} else {
    99  		value = strings.ReplaceAll(valueStr, "\\,", ",")
   100  	}
   101  	return value
   102  }
   103  
   104  // ConsolidateLog is a helper function to dedup the log message.
   105  func ConsolidateLog(logMessage string) string {
   106  	logCountMap := make(map[string]int)
   107  	stderrSlice := strings.Split(logMessage, "\n")
   108  	for _, item := range stderrSlice {
   109  		if item == "" {
   110  			continue
   111  		}
   112  		_, exist := logCountMap[item]
   113  		if exist {
   114  			logCountMap[item]++
   115  		} else {
   116  			logCountMap[item] = 1
   117  		}
   118  	}
   119  	var sb strings.Builder
   120  	for _, item := range stderrSlice {
   121  		if logCountMap[item] == 0 {
   122  			continue
   123  		}
   124  		sb.WriteString(fmt.Sprintf("%s (repeated %v times)\n", item, logCountMap[item]))
   125  		// reset seen log count
   126  		logCountMap[item] = 0
   127  	}
   128  	return sb.String()
   129  }
   130  
   131  // RenderTemplate is a helper method to render a template with the given values.
   132  func RenderTemplate(tmpl string, ts any) (string, error) {
   133  	t, err := template.New("").Parse(tmpl)
   134  	if err != nil {
   135  		return "", err
   136  	}
   137  	buf := new(bytes.Buffer)
   138  	err = t.Execute(buf, ts)
   139  	if err != nil {
   140  		return "", err
   141  	}
   142  	return buf.String(), nil
   143  }
   144  
   145  func ValueString(v *structpb.Value) string {
   146  	switch x := v.Kind.(type) {
   147  	case *structpb.Value_StringValue:
   148  		return x.StringValue
   149  	case *structpb.Value_NumberValue:
   150  		return fmt.Sprint(x.NumberValue)
   151  	default:
   152  		return v.String()
   153  	}
   154  }
   155  
   156  func MustStruct(m map[string]any) *structpb.Struct {
   157  	s, _ := structpb.NewStruct(m)
   158  	return s
   159  }