|
5 | 5 | "encoding/json"
|
6 | 6 | "fmt"
|
7 | 7 | "io"
|
| 8 | + "io/fs" |
8 | 9 | "os"
|
9 | 10 | "path/filepath"
|
10 | 11 | "strings"
|
@@ -164,6 +165,56 @@ func ParseCompressedOCIArtifactIntoDesign(artifact []byte) (*pattern.PatternFile
|
164 | 165 | return &patternFile, nil
|
165 | 166 | }
|
166 | 167 |
|
| 168 | +// thsi attempts to locate and parse a design inside the extracted bundle |
| 169 | +func preferBundleDesign(sf SanitizedFile) (*pattern.PatternFile, error) { |
| 170 | + if sf.ExtractedContentPath == "" { |
| 171 | + return nil, fmt.Errorf("extracted path empty") |
| 172 | + } |
| 173 | + |
| 174 | + candidateRoot := filepath.Join(sf.ExtractedContentPath, ".meshery", "content") |
| 175 | + if _, err := os.Stat(candidateRoot); err != nil { |
| 176 | + return nil, err |
| 177 | + } |
| 178 | + |
| 179 | + return walkForDesignYML(candidateRoot) |
| 180 | +} |
| 181 | + |
| 182 | +// walkForDesignYML searches recursively for a design.yml file and decodes it. |
| 183 | +func walkForDesignYML(root string) (*pattern.PatternFile, error) { |
| 184 | + var designPath string |
| 185 | + err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { |
| 186 | + if err != nil { |
| 187 | + return err |
| 188 | + } |
| 189 | + if d.IsDir() { |
| 190 | + return nil |
| 191 | + } |
| 192 | + if strings.EqualFold(filepath.Base(path), "design.yml") { |
| 193 | + designPath = path |
| 194 | + return io.EOF |
| 195 | + } |
| 196 | + return nil |
| 197 | + }) |
| 198 | + if err != nil && err != io.EOF { |
| 199 | + return nil, err |
| 200 | + } |
| 201 | + if designPath == "" { |
| 202 | + return nil, fmt.Errorf("design.yml not found under %s", root) |
| 203 | + } |
| 204 | + |
| 205 | + data, err := os.ReadFile(designPath) |
| 206 | + if err != nil { |
| 207 | + return nil, err |
| 208 | + } |
| 209 | + |
| 210 | + var pf pattern.PatternFile |
| 211 | + if err := yaml.Unmarshal(data, &pf); err != nil { |
| 212 | + return nil, err |
| 213 | + } |
| 214 | + pf.Name = filepath.Base(designPath) |
| 215 | + return &pf, nil |
| 216 | +} |
| 217 | + |
167 | 218 | // we are allowing unknown fields to keep compabitibilty with old designs when
|
168 | 219 | // we make unversioned changes to schema
|
169 | 220 | func ParseFileAsMesheryDesign(file SanitizedFile) (pattern.PatternFile, error) {
|
@@ -200,12 +251,16 @@ func ParseFileAsMesheryDesign(file SanitizedFile) (pattern.PatternFile, error) {
|
200 | 251 | return pattern.PatternFile{}, utils.ErrInvalidConstructSchemaVersion("design", parsed.SchemaVersion, v1beta1.DesignSchemaVersion)
|
201 | 252 |
|
202 | 253 | case ".tgz", ".tar", ".tar.gz", ".zip": // try to parse oci artifacts
|
203 |
| - parsed_design, err := ParseCompressedOCIArtifactIntoDesign(file.RawData) |
204 |
| - if parsed_design == nil || err != nil { |
205 |
| - return pattern.PatternFile{}, err |
| 254 | + if pf, err := preferBundleDesign(file); err == nil { |
| 255 | + return *pf, nil |
206 | 256 | }
|
207 | 257 |
|
208 |
| - return *parsed_design, err |
| 258 | + // ─── 2️⃣ fall back to OCI‑layout tarball parsing ─── |
| 259 | + pf, err := ParseCompressedOCIArtifactIntoDesign(file.RawData) |
| 260 | + if err != nil { |
| 261 | + return pattern.PatternFile{}, err |
| 262 | + } |
| 263 | + return *pf, nil |
209 | 264 |
|
210 | 265 | default:
|
211 | 266 | return pattern.PatternFile{}, fmt.Errorf("Invalid File extension %s", file.FileExt)
|
|
0 commit comments