pkg/buildermetadata/buildermetadata.go (68 lines of code) (raw):
// Copyright 2025 Google LLC
//
// 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 buildermetadata provides an interface for builder metadata with text-based metrics.
package buildermetadata
import (
"encoding/json"
"sync"
)
var (
bmd *BuilderMetadata
mu sync.Mutex
once sync.Once
)
// BuilderMetadata contains the builder metadata to be reported to RCS via BuilderOutput.
type BuilderMetadata struct {
metadata map[MetadataID]MetadataValue
}
// NewBuilderMetadata returns a new, empty BuilderMetadata
func NewBuilderMetadata() BuilderMetadata {
return BuilderMetadata{make(map[MetadataID]MetadataValue)}
}
// MetadataValue is the metadata value corresponding to the MetadataID.
type MetadataValue string
// MetadataID is the unique identifier for each metadata value.
type MetadataID string
// The MetadataID enum below define new metadata that can be recorded.
// To add a new value, add a new const MetadataID below and
// the buildermetadata package will be able to track new metadata.
//
// Intended usage:
//
// buildermetadata.GlobalBuilderMetadata().SetValue(buildermetadata.IsUsingGenkit, "true")
const (
IsUsingGenkit MetadataID = "1" // Whether the application is using Genkit
IsUsingGenAI MetadataID = "2" // Whether the application is using GenAI API
)
// GetValue returns the Metadata value with MetadataID id, or creates it if it doesn't exist.
func (b *BuilderMetadata) GetValue(id MetadataID) MetadataValue {
if _, found := b.metadata[id]; !found {
b.metadata[id] = MetadataValue("false")
}
return b.metadata[id]
}
// SetValue sets the Metadata value with MetadataID id.
func (b *BuilderMetadata) SetValue(id MetadataID, value MetadataValue) {
b.metadata[id] = value
}
// ForEachValue iterates over all values in the BuilderMetadata.
func (b *BuilderMetadata) ForEachValue(f func(MetadataID, MetadataValue)) {
for id, value := range b.metadata {
f(id, value)
}
}
// Reset resets the state of the BuilderMetadata struct
// For testing use only.
func Reset() {
mu.Lock()
defer mu.Unlock()
bmd = &BuilderMetadata{make(map[MetadataID]MetadataValue)}
}
// GlobalBuilderMetadata returns a pointer to the BuilderMetadata singleton
func GlobalBuilderMetadata() *BuilderMetadata {
mu.Lock()
defer mu.Unlock()
once.Do(
func() {
bmd = &BuilderMetadata{make(map[MetadataID]MetadataValue)}
})
return bmd
}
type metadataMaps struct {
Metadata map[MetadataID]MetadataValue `json:"m,omitempty"`
}
// MarshalJSON is a custom marshaler for BuilderMetadata
func (b BuilderMetadata) MarshalJSON() ([]byte, error) {
return json.Marshal(metadataMaps{Metadata: b.metadata})
}
// UnmarshalJSON is a custom unmarshaller for BuilderMetadata
func (b *BuilderMetadata) UnmarshalJSON(j []byte) error {
var val metadataMaps
if err := json.Unmarshal(j, &val); err != nil {
return err
}
if val.Metadata == nil {
b.metadata = make(map[MetadataID]MetadataValue)
} else {
b.metadata = val.Metadata
}
return nil
}