1// Copyright 2024 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package release_config_lib 16 17import ( 18 "cmp" 19 "fmt" 20 "slices" 21 22 rc_proto "android/soong/cmd/release_config/release_config_proto" 23 24 "google.golang.org/protobuf/proto" 25) 26 27// A flag artifact, with its final value and declaration/override history. 28type FlagArtifact struct { 29 // The flag_declaration message. 30 FlagDeclaration *rc_proto.FlagDeclaration 31 32 // The index of the config directory where this flag was declared. 33 // Flag values cannot be set in a location with a lower index. 34 DeclarationIndex int 35 36 // A history of value assignments and overrides. 37 Traces []*rc_proto.Tracepoint 38 39 // The value of the flag. 40 Value *rc_proto.Value 41 42 // This flag is redacted. Set by UpdateValue when the FlagValue proto 43 // says to redact it. 44 Redacted bool 45} 46 47// Key is flag name. 48type FlagArtifacts map[string]*FlagArtifact 49 50func FlagArtifactFactory(declPath string) *FlagArtifact { 51 fd := &rc_proto.FlagDeclaration{} 52 fa := &FlagArtifact{ 53 FlagDeclaration: fd, 54 DeclarationIndex: -1, 55 Traces: []*rc_proto.Tracepoint{}, 56 } 57 if declPath != "" { 58 LoadMessage(declPath, fd) 59 fa.Value = fd.GetValue() 60 fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(declPath), Value: fa.Value}) 61 } 62 return fa 63} 64 65func FlagArtifactsFactory(artifactsPath string) *FlagArtifacts { 66 ret := make(FlagArtifacts) 67 if artifactsPath != "" { 68 fas := &rc_proto.FlagArtifacts{} 69 LoadMessage(artifactsPath, fas) 70 for _, fa_pb := range fas.FlagArtifacts { 71 fa := &FlagArtifact{} 72 fa.FlagDeclaration = fa_pb.GetFlagDeclaration() 73 if val := fa_pb.GetValue(); val != nil { 74 fa.Value = val 75 } 76 if traces := fa_pb.GetTraces(); traces != nil { 77 fa.Traces = traces 78 } 79 ret[*fa.FlagDeclaration.Name] = fa 80 } 81 } 82 return &ret 83} 84 85func (fas *FlagArtifacts) SortedFlagNames() []string { 86 var names []string 87 for k, _ := range *fas { 88 names = append(names, k) 89 } 90 slices.Sort(names) 91 return names 92} 93 94func (fa *FlagArtifact) GenerateFlagDeclarationArtifact() *rc_proto.FlagDeclarationArtifact { 95 ret := &rc_proto.FlagDeclarationArtifact{ 96 Name: fa.FlagDeclaration.Name, 97 DeclarationPath: fa.Traces[0].Source, 98 } 99 if namespace := fa.FlagDeclaration.GetNamespace(); namespace != "" { 100 ret.Namespace = proto.String(namespace) 101 } 102 if description := fa.FlagDeclaration.GetDescription(); description != "" { 103 ret.Description = proto.String(description) 104 } 105 if workflow := fa.FlagDeclaration.GetWorkflow(); workflow != rc_proto.Workflow_Workflow_Unspecified { 106 ret.Workflow = &workflow 107 } 108 if containers := fa.FlagDeclaration.GetContainers(); containers != nil { 109 ret.Containers = containers 110 } 111 return ret 112} 113 114func FlagDeclarationArtifactsFactory(path string) *rc_proto.FlagDeclarationArtifacts { 115 ret := &rc_proto.FlagDeclarationArtifacts{} 116 if path != "" { 117 LoadMessage(path, ret) 118 } else { 119 ret.FlagDeclarationArtifacts = []*rc_proto.FlagDeclarationArtifact{} 120 } 121 return ret 122} 123 124func (fas *FlagArtifacts) GenerateFlagDeclarationArtifacts(intermediates []*rc_proto.FlagDeclarationArtifacts) *rc_proto.FlagDeclarationArtifacts { 125 ret := &rc_proto.FlagDeclarationArtifacts{FlagDeclarationArtifacts: []*rc_proto.FlagDeclarationArtifact{}} 126 for _, fa := range *fas { 127 ret.FlagDeclarationArtifacts = append(ret.FlagDeclarationArtifacts, fa.GenerateFlagDeclarationArtifact()) 128 } 129 for _, fda := range intermediates { 130 ret.FlagDeclarationArtifacts = append(ret.FlagDeclarationArtifacts, fda.FlagDeclarationArtifacts...) 131 } 132 slices.SortFunc(ret.FlagDeclarationArtifacts, func(a, b *rc_proto.FlagDeclarationArtifact) int { 133 return cmp.Compare(*a.Name, *b.Name) 134 }) 135 return ret 136} 137 138// Create a clone of the flag artifact. 139// 140// Returns: 141// 142// *FlagArtifact: the copy of the artifact. 143func (src *FlagArtifact) Clone() *FlagArtifact { 144 value := &rc_proto.Value{} 145 proto.Merge(value, src.Value) 146 return &FlagArtifact{ 147 FlagDeclaration: src.FlagDeclaration, 148 Traces: src.Traces, 149 Value: value, 150 DeclarationIndex: src.DeclarationIndex, 151 Redacted: src.Redacted, 152 } 153} 154 155// Clone FlagArtifacts. 156// 157// Returns: 158// 159// FlagArtifacts: a copy of the source FlagArtifacts. 160func (src FlagArtifacts) Clone() (dst FlagArtifacts) { 161 if dst == nil { 162 dst = make(FlagArtifacts) 163 } 164 for k, v := range src { 165 dst[k] = v.Clone() 166 } 167 return 168} 169 170// Update the value of a flag. 171// 172// This appends to flagArtifact.Traces, and updates flagArtifact.Value. 173// 174// Args: 175// 176// flagValue FlagValue: the value to assign 177// 178// Returns: 179// 180// error: any error encountered 181func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error { 182 name := *flagValue.proto.Name 183 fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value}) 184 if flagValue.proto.GetRedacted() { 185 fa.Redacted = true 186 fmt.Printf("Redacting flag %s in %s\n", name, flagValue.path) 187 return nil 188 } 189 if fa.Value.GetObsolete() { 190 return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces) 191 } 192 var newValue *rc_proto.Value 193 switch val := flagValue.proto.Value.Val.(type) { 194 case *rc_proto.Value_StringValue: 195 newValue = &rc_proto.Value{Val: &rc_proto.Value_StringValue{val.StringValue}} 196 case *rc_proto.Value_BoolValue: 197 newValue = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{val.BoolValue}} 198 case *rc_proto.Value_Obsolete: 199 if !val.Obsolete { 200 return fmt.Errorf("%s: Cannot set obsolete=false. Trace=%v", name, fa.Traces) 201 } 202 newValue = &rc_proto.Value{Val: &rc_proto.Value_Obsolete{true}} 203 default: 204 return fmt.Errorf("Invalid type for flag_value: %T. Trace=%v", val, fa.Traces) 205 } 206 if proto.Equal(newValue, fa.Value) { 207 warnf("%s: redundant override (set in %s)\n", flagValue.path, *fa.Traces[len(fa.Traces)-2].Source) 208 } 209 fa.Value = newValue 210 return nil 211} 212 213// Marshal the FlagArtifact into a flag_artifact message. 214func (fa *FlagArtifact) Marshal() (*rc_proto.FlagArtifact, error) { 215 if fa.Redacted { 216 return nil, nil 217 } 218 return &rc_proto.FlagArtifact{ 219 FlagDeclaration: fa.FlagDeclaration, 220 Value: fa.Value, 221 Traces: fa.Traces, 222 }, nil 223} 224 225// Marshal the FlagArtifact without Traces. 226func (fa *FlagArtifact) MarshalWithoutTraces() (*rc_proto.FlagArtifact, error) { 227 if fa.Redacted { 228 return nil, nil 229 } 230 return &rc_proto.FlagArtifact{ 231 FlagDeclaration: fa.FlagDeclaration, 232 Value: fa.Value, 233 }, nil 234} 235