Skip to content

Commit 2c7f0cf

Browse files
committed
alternative approach to regup yaml parsing
Signed-off-by: Juan Antonio Osorio <[email protected]>
1 parent 151ab9b commit 2c7f0cf

File tree

3 files changed

+175
-12
lines changed

3 files changed

+175
-12
lines changed

cmd/regup/main.go

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"strings"
1414
"time"
1515

16+
"github.com/goccy/go-yaml/ast"
17+
"github.com/goccy/go-yaml/parser"
1618
"github.com/spf13/cobra"
1719
"github.com/stacklok/toolhive-registry/pkg/types"
1820
"github.com/stacklok/toolhive/pkg/container/verifier"
@@ -198,22 +200,131 @@ func updateServerInfo(server serverWithName) error {
198200
logger.Infof("Updating %s: stars %d -> %d, pulls %d -> %d",
199201
server.name, currentStars, newStars, currentPulls, newPulls)
200202

201-
// Update the metadata
202-
server.entry.Metadata.Stars = newStars
203-
server.entry.Metadata.Pulls = newPulls
204-
server.entry.Metadata.LastUpdated = time.Now().UTC().Format(time.RFC3339)
203+
// Use goccy/go-yaml to preserve comments and structure
204+
return updateYAMLPreservingStructure(server.path, newStars, newPulls)
205+
}
205206

206-
// Save the updated spec back to file
207-
data, err := yaml.Marshal(server.entry)
207+
// updateYAMLPreservingStructure updates the YAML file while preserving comments and structure
208+
func updateYAMLPreservingStructure(path string, stars, pulls int) error {
209+
// Read the original file
210+
data, err := os.ReadFile(path)
208211
if err != nil {
209-
return fmt.Errorf("failed to marshal YAML: %w", err)
212+
return fmt.Errorf("failed to read file: %w", err)
210213
}
211214

212-
if err := os.WriteFile(server.path, data, 0644); err != nil {
213-
return fmt.Errorf("failed to write spec file: %w", err)
215+
// Parse the YAML preserving comments
216+
file, err := parser.ParseBytes(data, parser.ParseComments)
217+
if err != nil {
218+
return fmt.Errorf("failed to parse YAML: %w", err)
214219
}
215220

216-
return nil
221+
// Find and update the metadata section
222+
for _, doc := range file.Docs {
223+
if err := updateMetadataInAST(doc.Body, stars, pulls); err != nil {
224+
// If metadata doesn't exist, we need to add it
225+
if err.Error() == "metadata not found" {
226+
addMetadataToAST(doc.Body, stars, pulls)
227+
} else {
228+
return err
229+
}
230+
}
231+
}
232+
233+
// Write back to file
234+
return os.WriteFile(path, []byte(file.String()), 0644)
235+
}
236+
237+
// updateMetadataInAST updates metadata fields in the AST
238+
func updateMetadataInAST(node ast.Node, stars, pulls int) error {
239+
mapping, ok := node.(*ast.MappingNode)
240+
if !ok {
241+
return fmt.Errorf("expected mapping node")
242+
}
243+
244+
for _, value := range mapping.Values {
245+
if value.Key.String() == "metadata" {
246+
metaMapping, ok := value.Value.(*ast.MappingNode)
247+
if !ok {
248+
continue
249+
}
250+
251+
// Update existing fields
252+
hasStars, hasPulls, hasLastUpdated := false, false, false
253+
for _, metaValue := range metaMapping.Values {
254+
switch metaValue.Key.String() {
255+
case "stars":
256+
metaValue.Value = &ast.IntegerNode{
257+
Value: fmt.Sprintf("%d", stars),
258+
}
259+
hasStars = true
260+
case "pulls":
261+
metaValue.Value = &ast.IntegerNode{
262+
Value: fmt.Sprintf("%d", pulls),
263+
}
264+
hasPulls = true
265+
case "lastupdated":
266+
metaValue.Value = &ast.StringNode{
267+
Value: time.Now().UTC().Format(time.RFC3339),
268+
}
269+
hasLastUpdated = true
270+
}
271+
}
272+
273+
// Add missing fields
274+
if !hasStars {
275+
metaMapping.Values = append(metaMapping.Values, &ast.MappingValueNode{
276+
Key: &ast.StringNode{Value: "stars"},
277+
Value: &ast.IntegerNode{Value: fmt.Sprintf("%d", stars)},
278+
})
279+
}
280+
if !hasPulls {
281+
metaMapping.Values = append(metaMapping.Values, &ast.MappingValueNode{
282+
Key: &ast.StringNode{Value: "pulls"},
283+
Value: &ast.IntegerNode{Value: fmt.Sprintf("%d", pulls)},
284+
})
285+
}
286+
if !hasLastUpdated {
287+
metaMapping.Values = append(metaMapping.Values, &ast.MappingValueNode{
288+
Key: &ast.StringNode{Value: "lastupdated"},
289+
Value: &ast.StringNode{Value: time.Now().UTC().Format(time.RFC3339)},
290+
})
291+
}
292+
293+
return nil
294+
}
295+
}
296+
297+
return fmt.Errorf("metadata not found")
298+
}
299+
300+
// addMetadataToAST adds a metadata section to the AST
301+
func addMetadataToAST(node ast.Node, stars, pulls int) {
302+
mapping, ok := node.(*ast.MappingNode)
303+
if !ok {
304+
return
305+
}
306+
307+
metaMapping := &ast.MappingNode{
308+
Values: []*ast.MappingValueNode{
309+
{
310+
Key: &ast.StringNode{Value: "stars"},
311+
Value: &ast.IntegerNode{Value: fmt.Sprintf("%d", stars)},
312+
},
313+
{
314+
Key: &ast.StringNode{Value: "pulls"},
315+
Value: &ast.IntegerNode{Value: fmt.Sprintf("%d", pulls)},
316+
},
317+
{
318+
Key: &ast.StringNode{Value: "lastupdated"},
319+
Value: &ast.StringNode{Value: time.Now().UTC().Format(time.RFC3339)},
320+
},
321+
},
322+
}
323+
324+
mapping.Values = append(mapping.Values, &ast.MappingValueNode{
325+
Key: &ast.StringNode{Value: "metadata"},
326+
Value: metaMapping,
327+
})
217328
}
218329

219330
// verifyServerProvenance verifies the provenance information for a server

go.mod

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ require (
2828
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
2929
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
3030
github.com/Microsoft/go-winio v0.6.2 // indirect
31+
github.com/a8m/envsubst v1.4.3 // indirect
3132
github.com/adrg/xdg v0.5.3 // indirect
33+
github.com/alecthomas/participle/v2 v2.1.4 // indirect
3234
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
3335
github.com/avast/retry-go/v4 v4.6.1 // indirect
3436
github.com/blang/semver v3.5.1+incompatible // indirect
@@ -43,6 +45,7 @@ require (
4345
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
4446
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
4547
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
48+
github.com/dimchansky/utfbom v1.1.1 // indirect
4649
github.com/distribution/reference v0.6.0 // indirect
4750
github.com/docker/cli v28.2.2+incompatible // indirect
4851
github.com/docker/distribution v2.8.3+incompatible // indirect
@@ -51,13 +54,16 @@ require (
5154
github.com/docker/go-connections v0.6.0 // indirect
5255
github.com/docker/go-units v0.5.0 // indirect
5356
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a // indirect
57+
github.com/elliotchance/orderedmap v1.8.0 // indirect
5458
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
5559
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
5660
github.com/extism/go-sdk v1.7.0 // indirect
61+
github.com/fatih/color v1.18.0 // indirect
5762
github.com/felixge/httpsnoop v1.0.4 // indirect
5863
github.com/fsnotify/fsnotify v1.8.0 // indirect
5964
github.com/globocom/go-buffer v1.2.2 // indirect
6065
github.com/go-chi/chi v4.1.2+incompatible // indirect
66+
github.com/go-ini/ini v1.67.0 // indirect
6167
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
6268
github.com/go-logr/logr v1.4.3 // indirect
6369
github.com/go-logr/stdr v1.2.2 // indirect
@@ -73,6 +79,8 @@ require (
7379
github.com/go-openapi/validate v0.24.0 // indirect
7480
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
7581
github.com/gobwas/glob v0.2.3 // indirect
82+
github.com/goccy/go-json v0.10.5 // indirect
83+
github.com/goccy/go-yaml v1.18.0 // indirect
7684
github.com/godbus/dbus/v5 v5.1.0 // indirect
7785
github.com/gofrs/flock v0.12.1 // indirect
7886
github.com/gogo/protobuf v1.3.2 // indirect
@@ -91,19 +99,24 @@ require (
9199
github.com/in-toto/in-toto-golang v0.9.0 // indirect
92100
github.com/inconshreveable/mousetrap v1.1.0 // indirect
93101
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b // indirect
102+
github.com/jinzhu/copier v0.4.0 // indirect
94103
github.com/josharian/intern v1.0.0 // indirect
95104
github.com/klauspost/compress v1.18.0 // indirect
96105
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
97106
github.com/lmittmann/tint v1.1.2 // indirect
107+
github.com/magiconair/properties v1.8.10 // indirect
98108
github.com/mailru/easyjson v0.9.0 // indirect
109+
github.com/mattn/go-colorable v0.1.14 // indirect
110+
github.com/mattn/go-isatty v0.0.20 // indirect
111+
github.com/mikefarah/yq/v4 v4.47.1 // indirect
99112
github.com/mitchellh/go-homedir v1.1.0 // indirect
100113
github.com/mitchellh/mapstructure v1.5.0 // indirect
101114
github.com/moby/docker-image-spec v1.3.1 // indirect
102115
github.com/oklog/ulid v1.3.1 // indirect
103116
github.com/opencontainers/go-digest v1.0.0 // indirect
104117
github.com/opencontainers/image-spec v1.1.1 // indirect
105118
github.com/opentracing/opentracing-go v1.2.0 // indirect
106-
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
119+
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
107120
github.com/pkg/errors v0.9.1 // indirect
108121
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
109122
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
@@ -121,7 +134,7 @@ require (
121134
github.com/sourcegraph/conc v0.3.0 // indirect
122135
github.com/spf13/afero v1.12.0 // indirect
123136
github.com/spf13/cast v1.7.1 // indirect
124-
github.com/spf13/pflag v1.0.6 // indirect
137+
github.com/spf13/pflag v1.0.7 // indirect
125138
github.com/spf13/viper v1.20.1 // indirect
126139
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
127140
github.com/subosito/gotenv v1.6.0 // indirect
@@ -134,6 +147,7 @@ require (
134147
github.com/transparency-dev/merkle v0.0.2 // indirect
135148
github.com/transparency-dev/tessera v0.2.1-0.20250610150926-8ee4e93b2823 // indirect
136149
github.com/vbatts/tar-split v0.12.1 // indirect
150+
github.com/yuin/gopher-lua v1.1.1 // indirect
137151
github.com/zalando/go-keyring v0.2.6 // indirect
138152
github.com/zeebo/errs v1.4.0 // indirect
139153
go.mongodb.org/mongo-driver v1.14.0 // indirect
@@ -150,6 +164,7 @@ require (
150164
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
151165
go.uber.org/multierr v1.11.0 // indirect
152166
go.uber.org/zap v1.27.0 // indirect
167+
go.yaml.in/yaml/v3 v3.0.4 // indirect
153168
golang.org/x/crypto v0.40.0 // indirect
154169
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
155170
golang.org/x/mod v0.27.0 // indirect
@@ -166,5 +181,6 @@ require (
166181
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
167182
google.golang.org/grpc v1.73.0 // indirect
168183
google.golang.org/protobuf v1.36.6 // indirect
184+
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect
169185
k8s.io/klog/v2 v2.130.1 // indirect
170186
)

0 commit comments

Comments
 (0)