func NormalizeForFilename(name string) string {
	processedString := MakeFileNameCompliant(name)
	const maxPrefixLength = 15
	if len(processedString) > maxPrefixLength {
		processedString = processedString[0:maxPrefixLength]
	}
	crc64Table := crc64.MakeTable(0xC96C5795D7870F42)
	crc64Int := crc64.Checksum([]byte(name), crc64Table)
	return processedString + "-" + strconv.FormatUint(crc64Int, 16)
}
NormalizeForFilename normalizes a string to only filename valid characters
package common
import (
	"bytes"
	"crypto/sha256"
	"embed"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"hash/crc64"
	"io"
	"io/ioutil"
	"math"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"text/template"
	"github.com/go-git/go-git/v5"
	"github.com/konveyor/move2kube/filesystem"
	"github.com/konveyor/move2kube/types"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
	"github.com/xrash/smetrics"
	"gopkg.in/yaml.v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)
func GetFilesByExt(inputPath string, exts []string) ([]string, error) {
	var files []string
	if info, err := os.Stat(inputPath); os.IsNotExist(err) {
		logrus.Warnf("Error in walking through files due to : %q", err)
		return nil, err
	} else if !info.IsDir() {
		logrus.Warnf("The path %q is not a directory.", inputPath)
	}
	err := filepath.Walk(inputPath, func(path string, info os.FileInfo, err error) error {
		if err != nil && path == inputPath {  
			return err
		}
		if err != nil {
			logrus.Warnf("Skipping path %q due to error: %q", path, err)
			return nil
		}
		if info.IsDir() {
			for _, dirRegExp := range DefaultIgnoreDirRegexps {
				if dirRegExp.Match([]byte(filepath.Base(path))) {
					return filepath.SkipDir
				}
			}
			return nil
		}
		fext := filepath.Ext(path)
		for _, ext := range exts {
			if fext == ext {
				files = append(files, path)
			}
		}
		return nil
	})
	if err != nil {
		logrus.Warnf("Error in walking through files due to : %q", err)
		return files, err
	}
	logrus.Debugf("No of files with %s ext identified : %d", exts, len(files))
	return files, nil
}
func GetFilesByName(inputPath string, names []string, nameRegexes []string) ([]string, error) {
	var files []string
	if info, err := os.Stat(inputPath); os.IsNotExist(err) {
		logrus.Warnf("Error in walking through files due to : %q", err)
		return files, err
	} else if !info.IsDir() {
		logrus.Warnf("The path %q is not a directory.", inputPath)
	}
	compiledNameRegexes := []*regexp.Regexp{}
	for _, nameRegex := range nameRegexes {
		compiledNameRegex, err := regexp.Compile(nameRegex)
		if err != nil {
			logrus.Errorf("Could not compile regular expression (%s): %s. Ignoring regex during search", err, nameRegex)
			continue
		}
		compiledNameRegexes = append(compiledNameRegexes, compiledNameRegex)
	}
	err := filepath.Walk(inputPath, func(path string, info os.FileInfo, err error) error {
		if err != nil && path == inputPath {  
			return err
		}
		if err != nil {
			logrus.Warnf("Skipping path %q due to error: %q", path, err)
			return nil
		}
		if info.IsDir() {
			for _, dirRegExp := range DefaultIgnoreDirRegexps {
				if dirRegExp.Match([]byte(filepath.Base(path))) {
					return filepath.SkipDir
				}
			}
			return nil
		}
		fname := filepath.Base(path)
		for _, name := range names {
			if name == fname {
				files = append(files, path)
				return nil
			}
		}
		for _, compiledNameRegex := range compiledNameRegexes {
			if compiledNameRegex.MatchString(fname) {
				files = append(files, path)
				return nil
			}
		}
		return nil
	})
	if err != nil {
		logrus.Warnf("Error in walking through files due to : %s", err)
		return files, err
	}
	logrus.Debugf("No of files with %s names identified : %d", names, len(files))
	return files, nil
}
func GetFilesInCurrentDirectory(path string, fileNames, fileNameRegexes []string) (files []string, err error) {
	files = []string{}
	dirhandle, err := os.Open(path)
	if err != nil {
		logrus.Errorf("Unable to open directory: %s", err)
		return nil, err
	}
	defer dirhandle.Close()
	compiledNameRegexes := []*regexp.Regexp{}
	for _, nameRegex := range fileNameRegexes {
		compiledNameRegex, err := regexp.Compile(nameRegex)
		if err != nil {
			logrus.Errorf("Could not compile regular expression (%s): %s. Ignoring regex during search", err, nameRegex)
			continue
		}
		compiledNameRegexes = append(compiledNameRegexes, compiledNameRegex)
	}
	currFileNames, err := dirhandle.Readdirnames(0)  
	if err != nil {
		logrus.Errorf("Unable to read dir names in %s : %s", path, err)
		return nil, err
	}
	for _, fname := range currFileNames {
		for _, name := range fileNames {
			if name == fname {
				files = append(files, filepath.Join(path, fname))
			}
		}
		for _, compiledNameRegex := range compiledNameRegexes {
			if compiledNameRegex.MatchString(fname) {
				files = append(files, filepath.Join(path, fname))
			}
		}
	}
	return files, nil
}
func YamlAttrPresent(path string, attr string) (bool, interface{}) {
	yamlFile, err := ioutil.ReadFile(path)
	if err != nil {
		logrus.Warnf("Error in reading yaml file %s: %s. Skipping", path, err)
		return false, nil
	}
	var fileContents map[string]interface{}
	err = yaml.Unmarshal(yamlFile, &fileContents)
	if err != nil {
		logrus.Warnf("Error in unmarshalling yaml file %s: %s. Skipping", path, err)
		return false, nil
	}
	if value, ok := fileContents[attr]; ok {
		logrus.Debugf("%s file has %s attribute", path, attr)
		return true, value
	}
	return false, nil
}
func GetImageNameAndTag(image string) (string, string) {
	parts := strings.Split(image, "/")
	imageAndTag := strings.Split(parts[len(parts)-1], ":")
	imageName := imageAndTag[0]
	var tag string
	if len(imageAndTag) == 1 {
		tag = "latest"
	} else {
		tag = imageAndTag[1]
	}
	return imageName, tag
}
func ObjectToYamlBytes(data interface{}) ([]byte, error) {
	var b bytes.Buffer
	encoder := yaml.NewEncoder(&b)
	encoder.SetIndent(2)
	if err := encoder.Encode(data); err != nil {
		logrus.Errorf("Failed to encode the object to yaml. Error: %q", err)
		return nil, err
	}
	if err := encoder.Close(); err != nil {
		logrus.Errorf("Failed to close the yaml encoder. Error: %q", err)
		return nil, err
	}
	return b.Bytes(), nil
}
func WriteYaml(outputPath string, data interface{}) error {
	yamlBytes, err := ObjectToYamlBytes(data)
	if err != nil {
		logrus.Errorf("Failed to encode the object as a yaml string. Error: %q", err)
		return err
	}
	return ioutil.WriteFile(outputPath, yamlBytes, DefaultFilePermission)
}
func ReadYaml(file string, data interface{}) error {
	yamlFile, err := ioutil.ReadFile(file)
	if err != nil {
		logrus.Debugf("Error in reading yaml file %s: %s.", file, err)
		return err
	}
	err = yaml.Unmarshal(yamlFile, data)
	if err != nil {
		logrus.Debugf("Error in unmarshalling yaml file %s: %s.", file, err)
		return err
	}
	rv := reflect.ValueOf(data)
	if rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Struct {
		rv = rv.Elem()
		fv := rv.FieldByName("APIVersion")
		if fv.IsValid() {
			if fv.Kind() == reflect.String {
				val := strings.TrimSpace(fv.String())
				if strings.HasPrefix(val, types.SchemeGroupVersion.Group) && !strings.HasSuffix(val, types.SchemeGroupVersion.Version) {
					logrus.Warnf("The application file (%s) was generated using a different version than (%s)", val, types.SchemeGroupVersion.String())
				}
			}
		}
	}
	return nil
}
func ReadMove2KubeYaml(path string, out interface{}) error {
	yamlData, err := ioutil.ReadFile(path)
	if err != nil {
		logrus.Errorf("Failed to read the yaml file at path %s Error: %q", path, err)
		return err
	}
	yamlMap := map[string]interface{}{}
	if err := yaml.Unmarshal([]byte(yamlData), yamlMap); err != nil {
		logrus.Debugf("Error occurred while unmarshalling yaml file at path %s Error: %q", path, err)
		return err
	}
	groupVersionI, ok := yamlMap["apiVersion"]
	if !ok {
		err := fmt.Errorf("did not find apiVersion in the yaml file at path %s", path)
		logrus.Debug(err)
		return err
	}
	groupVersionStr, ok := groupVersionI.(string)
	if !ok {
		err := fmt.Errorf("the apiVersion is not a string in the yaml file at path %s", path)
		logrus.Debug(err)
		return err
	}
	groupVersion, err := schema.ParseGroupVersion(groupVersionStr)
	if err != nil {
		logrus.Debugf("Failed to parse the apiVersion %s Error: %q", groupVersionStr, err)
		return err
	}
	if groupVersion.Group != types.SchemeGroupVersion.Group {
		err := fmt.Errorf("the file at path %s doesn't have the correct group. Expected group %s Actual group %s", path, types.SchemeGroupVersion.Group, groupVersion.Group)
		logrus.Debug(err)
		return err
	}
	if groupVersion.Version != types.SchemeGroupVersion.Version {
		logrus.Warnf("The file at path %s was generated using a different version. File version is %s and move2kube version is %s", path, groupVersion.Version, types.SchemeGroupVersion.Version)
	}
	if err := yaml.Unmarshal(yamlData, out); err != nil {
		logrus.Debugf("Error occurred while unmarshalling yaml file at path %s Error: %q", path, err)
		return err
	}
	return nil
}
func ReadMove2KubeYamlStrict(path string, out interface{}, kind string) error {
	yamlData, err := ioutil.ReadFile(path)
	if err != nil {
		logrus.Debugf("Failed to read the yaml file at path %s Error: %q", path, err)
		return err
	}
	yamlMap := map[string]interface{}{}
	if err := yaml.Unmarshal([]byte(yamlData), yamlMap); err != nil {
		logrus.Debugf("Error occurred while unmarshalling yaml file at path %s Error: %q", path, err)
		return err
	}
	groupVersionI, ok := yamlMap["apiVersion"]
	if !ok {
		err := fmt.Errorf("did not find apiVersion in the yaml file at path %s", path)
		logrus.Debug(err)
		return err
	}
	groupVersionStr, ok := groupVersionI.(string)
	if !ok {
		err := fmt.Errorf("the apiVersion is not a string in the yaml file at path %s", path)
		logrus.Debug(err)
		return err
	}
	groupVersion, err := schema.ParseGroupVersion(groupVersionStr)
	if err != nil {
		logrus.Debugf("Failed to parse the apiVersion %s Error: %q", groupVersionStr, err)
		return err
	}
	if groupVersion.Group != types.SchemeGroupVersion.Group {
		err := fmt.Errorf("the file at path %s doesn't have the correct group. Expected group %s Actual group %s", path, types.SchemeGroupVersion.Group, groupVersion.Group)
		logrus.Debug(err)
		return err
	}
	if groupVersion.Version != types.SchemeGroupVersion.Version {
		logrus.Warnf("The file at path %s was generated using a different version. File version is %s and move2kube version is %s", path, groupVersion.Version, types.SchemeGroupVersion.Version)
	}
	actualKindI, ok := yamlMap["kind"]
	if !ok {
		err := fmt.Errorf("the file at path %s does not have a kind specified", path)
		logrus.Debug(err)
		return err
	}
	actualKind, ok := actualKindI.(string)
	if !ok {
		err := fmt.Errorf("the kind is not a string in the yaml file at path %s", path)
		logrus.Debug(err)
		return err
	}
	if kind != "" && actualKind != kind {
		err := fmt.Errorf("the file at path %s does not have the expected kind. Expected: %s Actual: %s", path, kind, actualKind)
		logrus.Debug(err)
		return err
	}
	jsonBytes, err := json.Marshal(yamlMap)
	if err != nil {
		return err
	}
	dec := json.NewDecoder(bytes.NewReader(jsonBytes))
	dec.DisallowUnknownFields()
	if err := dec.Decode(out); err != nil {
		logrus.Debugf("Error occurred while unmarshalling yaml file at path %s Error: %q", path, err)
		return err
	}
	return nil
}
func WriteJSON(outputPath string, data interface{}) error {
	var b bytes.Buffer
	encoder := json.NewEncoder(&b)
	if err := encoder.Encode(data); err != nil {
		logrus.Error("Error while Encoding object")
		return err
	}
	err := ioutil.WriteFile(outputPath, b.Bytes(), DefaultFilePermission)
	if err != nil {
		logrus.Errorf("Error writing json to file: %s", err)
		return err
	}
	return nil
}
func ReadJSON(file string, data interface{}) error {
	jsonFile, err := ioutil.ReadFile(file)
	if err != nil {
		logrus.Debugf("Error in reading json file %s: %s.", file, err)
		return err
	}
	jsonFile = bytes.TrimPrefix(jsonFile, []byte("\xef\xbb\xbf"))
	err = json.Unmarshal(jsonFile, &data)
	if err != nil {
		logrus.Debugf("Error in unmarshalling json file %s: %s.", file, err)
		return err
	}
	return nil
}
func ReadXML(file string, data interface{}) error {
	xmlFile, err := ioutil.ReadFile(file)
	if err != nil {
		logrus.Debugf("Error in reading xml file %s: %s.", file, err)
		return err
	}
	err = xml.Unmarshal(xmlFile, &data)
	if err != nil {
		logrus.Debugf("Error in unmarshalling xml file %s: %s.", file, err)
		return err
	}
	return nil
}