| // Copyright Istio Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package yml |
| |
| import ( |
| "fmt" |
| "os" |
| "strings" |
| ) |
| |
| import ( |
| "github.com/apache/dubbo-go-pixiu/pkg/test" |
| ) |
| |
| type docType string |
| |
| const ( |
| namespacesAndCRDs docType = "namespaces_and_crds" |
| misc docType = "misc" |
| ) |
| |
| // FileWriter write YAML content to files. |
| type FileWriter interface { |
| // WriteYAML writes the given YAML content to one or more YAML files. |
| WriteYAML(filenamePrefix string, contents ...string) ([]string, error) |
| |
| // WriteYAMLOrFail calls WriteYAML and fails the test if an error occurs. |
| WriteYAMLOrFail(t test.Failer, filenamePrefix string, contents ...string) []string |
| } |
| |
| type writerImpl struct { |
| workDir string |
| } |
| |
| // NewFileWriter creates a new FileWriter that stores files under workDir. |
| func NewFileWriter(workDir string) FileWriter { |
| return &writerImpl{ |
| workDir: workDir, |
| } |
| } |
| |
| // WriteYAML writes the given YAML content to one or more YAML files. |
| func (w *writerImpl) WriteYAML(filenamePrefix string, contents ...string) ([]string, error) { |
| out := make([]string, 0, len(contents)) |
| content := JoinString(contents...) |
| files, err := splitContentsToFiles(w.workDir, content, filenamePrefix) |
| if err != nil { |
| return nil, err |
| } |
| |
| if len(files) == 0 { |
| f, err := writeContentsToTempFile(w.workDir, content) |
| if err != nil { |
| return nil, err |
| } |
| files = append(files, f) |
| } |
| out = append(out, files...) |
| return out, nil |
| } |
| |
| // WriteYAMLOrFial calls WriteYAML and fails the test if an error occurs. |
| func (w *writerImpl) WriteYAMLOrFail(t test.Failer, filenamePrefix string, contents ...string) []string { |
| t.Helper() |
| out, err := w.WriteYAML(filenamePrefix, contents...) |
| if err != nil { |
| t.Fatal(err) |
| } |
| return out |
| } |
| |
| func writeContentsToTempFile(workDir, contents string) (filename string, err error) { |
| defer func() { |
| if err != nil && filename != "" { |
| _ = os.Remove(filename) |
| filename = "" |
| } |
| }() |
| |
| var f *os.File |
| f, err = os.CreateTemp(workDir, yamlToFilename(contents)+".*.yaml") |
| if err != nil { |
| return |
| } |
| filename = f.Name() |
| |
| _, err = f.WriteString(contents) |
| return |
| } |
| |
| func yamlToFilename(contents string) string { |
| spl := SplitYamlByKind(contents) |
| delete(spl, "") |
| types := []string{} |
| for k := range spl { |
| types = append(types, k) |
| } |
| switch len(types) { |
| case 0: |
| return "empty" |
| case 1: |
| m := GetMetadata(contents) |
| if len(m) == 0 { |
| return fmt.Sprintf("%s.%s", types[0], m[0].Name) |
| } |
| return types[0] |
| case 2, 3, 4: |
| return strings.Join(types, "-") |
| default: |
| return strings.Join(types[:4], "-") + "-more" |
| } |
| } |
| |
| func splitContentsToFiles(workDir, content, filenamePrefix string) ([]string, error) { |
| split := SplitYamlByKind(content) |
| namespacesAndCrds := &yamlDoc{ |
| docType: namespacesAndCRDs, |
| content: split["Namespace"], |
| } |
| misc := &yamlDoc{ |
| docType: misc, |
| content: split["CustomResourceDefinition"], |
| } |
| |
| // If all elements were put into a single doc just return an empty list, indicating that the original |
| // content should be used. |
| docs := []*yamlDoc{namespacesAndCrds, misc} |
| for _, doc := range docs { |
| if len(doc.content) == 0 { |
| return make([]string, 0), nil |
| } |
| } |
| |
| filesToApply := make([]string, 0, len(docs)) |
| for _, doc := range docs { |
| tfile, err := doc.toTempFile(workDir, filenamePrefix) |
| if err != nil { |
| return nil, err |
| } |
| filesToApply = append(filesToApply, tfile) |
| } |
| return filesToApply, nil |
| } |
| |
| type yamlDoc struct { |
| content string |
| docType docType |
| } |
| |
| func (d *yamlDoc) toTempFile(workDir, fileNamePrefix string) (string, error) { |
| f, err := os.CreateTemp(workDir, fmt.Sprintf("%s_%s.yaml", fileNamePrefix, d.docType)) |
| if err != nil { |
| return "", err |
| } |
| defer func() { _ = f.Close() }() |
| |
| name := f.Name() |
| |
| _, err = f.WriteString(d.content) |
| if err != nil { |
| return "", err |
| } |
| return name, nil |
| } |