@@ -6,9 +6,10 @@ import (
66 "fmt"
77 "io"
88 "net/http"
9+ "strings"
910
1011 "github.com/goccy/go-yaml"
11- "github.com/mitchellh/mapstructure "
12+ "github.com/goccy/go-yaml/ast "
1213)
1314
1415// Better userfacing struct
@@ -18,28 +19,48 @@ type ModuleStream struct {
1819}
1920
2021type Stream struct {
21- Name string `mapstructure:"name"`
22- Stream string `mapstructure:"stream"`
23- Version string `mapstructure:"version"`
24- Context string `mapstructure:"context"`
25- Arch string `mapstructure:"arch"`
26- Summary string `mapstructure:"summary"`
27- Description string `mapstructure:"description"`
28- Artifacts Artifacts `mapstructure:"artifacts"`
29- Profiles map [string ]RpmProfiles `mapstructure:"profiles"`
22+ Name string `yaml:"name"`
23+ Stream StreamVersion `yaml:"stream"`
24+ Version string `yaml:"version"`
25+ Context string `yaml:"context"`
26+ Arch string `yaml:"arch"`
27+ Summary string `yaml:"summary"`
28+ Description string `yaml:"description"`
29+ Artifacts Artifacts `yaml:"artifacts"`
30+ Profiles map [string ]RpmProfiles `yaml:"profiles"`
31+ }
32+
33+ type StreamVersion string
34+
35+ // unmarshalStreamVersion ensures trailing zeros is preserved
36+ // in cases are the stream value is a float like 5.30
37+ func unmarshalStreamVersion (s * StreamVersion , data []byte ) error {
38+ str := strings .TrimSpace (string (data ))
39+
40+ //Remove additional quotes when stream is represented as string
41+ if len (str ) >= 2 && str [0 ] == '"' && str [len (str )- 1 ] == '"' {
42+ str = str [1 : len (str )- 1 ]
43+ }
44+
45+ * s = StreamVersion (str )
46+ return nil
47+ }
48+
49+ func (s StreamVersion ) String () string {
50+ return string (s )
3051}
3152
3253type RpmProfiles struct {
33- Rpms []string `mapstructure :"rpms"`
54+ Rpms []string `yaml :"rpms"`
3455}
3556
3657type Artifacts struct {
37- Rpms []string `mapstructure :"rpms"`
58+ Rpms []string `yaml :"rpms"`
3859}
3960
4061type ModuleMD struct {
41- Document string `mapstructure :"document"`
42- Version int `mapstructure :"version"`
62+ Document string `yaml :"document"`
63+ Version int `yaml :"version"`
4364 Data Stream `yaml:"data"`
4465}
4566
@@ -83,12 +104,10 @@ func (r *Repository) ModuleMDs(ctx context.Context) ([]ModuleMD, int, error) {
83104 return moduleMDs , 0 , err
84105}
85106
86- // parses modulemd objects from a given io reader
87- // modules yaml files include different types of documents which is hard to parse
88- // this implements a two step process:
89- //
90- // Parse each document into a map, with the value of interface, and then
91- // use mapstructure to parse the interface into a ModuleMD struct
107+ // parseModuleMDs moduleMDs contain multiple document types
108+ // this breaks parsing into two parts:
109+ // 1. use node to read the document type
110+ // 2. if the document type is modulemd, fully decode the value
92111func parseModuleMDs (body io.ReadCloser ) ([]ModuleMD , error ) {
93112 moduleMDs := make ([]ModuleMD , 0 )
94113
@@ -97,32 +116,30 @@ func parseModuleMDs(body io.ReadCloser) ([]ModuleMD, error) {
97116 return moduleMDs , fmt .Errorf ("error extracting compressed streams: %w" , err )
98117 }
99118
119+ yaml.RegisterCustomUnmarshaler [StreamVersion ](unmarshalStreamVersion )
120+
100121 decoder := yaml .NewDecoder (reader )
101122 for {
102- var doc map [string ]interface {}
103-
104- // Decode the next document
105- err := decoder .Decode (& doc )
123+ var node ast.Node
124+ err := decoder .Decode (& node )
106125 if err != nil {
107126 if errors .Is (err , io .EOF ) {
108127 break
109128 }
110129 return nil , fmt .Errorf ("error decoding streams: %w" , err )
111130 }
112- // Only care about modulemds right now
113- if doc ["document" ] == "modulemd" {
131+
132+ var docType struct {
133+ Document string `yaml:"document"`
134+ }
135+ if err := yaml .NodeToValue (node , & docType ); err != nil {
136+ return nil , fmt .Errorf ("error decoding document type: %w" , err )
137+ }
138+
139+ if docType .Document == "modulemd" {
114140 var module ModuleMD
115- config := & mapstructure.DecoderConfig {
116- WeaklyTypedInput : true ,
117- Result : & module ,
118- }
119- mapDecode , err := mapstructure .NewDecoder (config )
120- if err != nil {
121- return moduleMDs , fmt .Errorf ("error creating map decoder: %w" , err )
122- }
123- err = mapDecode .Decode (doc )
124- if err != nil {
125- return nil , fmt .Errorf ("error decoding map: %w" , err )
141+ if err := yaml .NodeToValue (node , & module ); err != nil {
142+ return nil , fmt .Errorf ("error decoding modulemd: %w" , err )
126143 }
127144 moduleMDs = append (moduleMDs , module )
128145 }
0 commit comments