blob: b7f7fab8d2176accab5dee7c1801ba550f2d52c5 [file] [log] [blame]
LaMont Jones1eccbf22024-04-08 09:09:35 -07001// 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 main
16
17import (
18 "cmp"
19 "encoding/json"
20 "flag"
21 "fmt"
22 "io/fs"
23 "os"
24 "path/filepath"
25 "slices"
26 "strings"
27
28 "android/soong/cmd/release_config/release_config_proto"
29
30 "google.golang.org/protobuf/encoding/prototext"
31 "google.golang.org/protobuf/proto"
32)
33
34var verboseFlag bool
35
36type StringList []string
37
38func (l *StringList) Set(v string) error {
39 *l = append(*l, v)
40 return nil
41}
42
43func (l *StringList) String() string {
44 return fmt.Sprintf("%v", *l)
45}
46
47var releaseConfigMapPaths StringList
48
49func DumpProtos(outDir string, message proto.Message) error {
50 basePath := filepath.Join(outDir, "all_release_configs")
51 writer := func(suffix string, marshal func() ([]byte, error)) error {
52 data, err := marshal()
53 if err != nil {
54 return err
55 }
56 return os.WriteFile(fmt.Sprintf("%s.%s", basePath, suffix), data, 0644)
57 }
58 err := writer("textproto", func() ([]byte, error) { return prototext.MarshalOptions{Multiline: true}.Marshal(message) })
59 if err != nil {
60 return err
61 }
62
63 err = writer("pb", func() ([]byte, error) { return proto.Marshal(message) })
64 if err != nil {
65 return err
66 }
67
68 return writer("json", func() ([]byte, error) { return json.MarshalIndent(message, "", " ") })
69}
70
71func LoadTextproto(path string, message proto.Message) error {
72 data, err := os.ReadFile(path)
73 if err != nil {
74 return err
75 }
76 ret := prototext.Unmarshal(data, message)
77 if verboseFlag {
78 debug, _ := prototext.Marshal(message)
79 fmt.Printf("%s: %s\n", path, debug)
80 }
81 return ret
82}
83
84func WalkTextprotoFiles(root string, subdir string, Func fs.WalkDirFunc) error {
85 path := filepath.Join(root, subdir)
86 if _, err := os.Stat(path); err != nil {
87 // Missing subdirs are not an error.
88 return nil
89 }
90 return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
91 if err != nil {
92 return err
93 }
94 if strings.HasSuffix(d.Name(), ".textproto") && d.Type().IsRegular() {
95 return Func(path, d, err)
96 }
97 return nil
98 })
99}
100
101type FlagValue struct {
102 // The path providing this value.
103 path string
104
105 // Protobuf
106 proto release_config_proto.FlagValue
107}
108
109func FlagValueFactory(protoPath string) (fv *FlagValue) {
110 fv = &FlagValue{path: protoPath}
111 if protoPath != "" {
112 LoadTextproto(protoPath, &fv.proto)
113 }
114 return fv
115}
116
117// One directory's contribution to the a release config.
118type ReleaseConfigContribution struct {
119 // Paths to files providing this config.
120 path string
121
122 // The index of the config directory where this release config
123 // contribution was declared.
124 // Flag values cannot be set in a location with a lower index.
125 DeclarationIndex int
126
127 // Protobufs relevant to the config.
128 proto release_config_proto.ReleaseConfig
129
130 FlagValues []*FlagValue
131}
132
133// A single release_config_map.textproto and its associated data.
134// Used primarily for debugging.
135type ReleaseConfigMap struct {
136 // The path to this release_config_map file.
137 path string
138
139 // Data received
140 proto release_config_proto.ReleaseConfigMap
141
142 ReleaseConfigContributions map[string]*ReleaseConfigContribution
143 FlagDeclarations []release_config_proto.FlagDeclaration
144}
145
146// A generated release config.
147type ReleaseConfig struct {
148 // the Name of the release config
149 Name string
150
151 // The index of the config directory where this release config was
152 // first declared.
153 // Flag values cannot be set in a location with a lower index.
154 DeclarationIndex int
155
156 // What contributes to this config.
157 Contributions []*ReleaseConfigContribution
158
159 // Aliases for this release
160 OtherNames []string
161
162 // The names of release configs that we inherit
163 InheritNames []string
164
165 // Unmarshalled flag artifacts
166 FlagArtifacts FlagArtifacts
167
168 // Generated release config
169 ReleaseConfigArtifact *release_config_proto.ReleaseConfigArtifact
170
171 // We have begun compiling this release config.
172 compileInProgress bool
173}
174
175type FlagArtifact struct {
176 FlagDeclaration *release_config_proto.FlagDeclaration
177
178 // The index of the config directory where this flag was declared.
179 // Flag values cannot be set in a location with a lower index.
180 DeclarationIndex int
181
182 Traces []*release_config_proto.Tracepoint
183
184 // Assigned value
185 Value *release_config_proto.Value
186}
187
188// Key is flag name.
189type FlagArtifacts map[string]*FlagArtifact
190
191type ReleaseConfigDirMap map[string]int
192
193// The generated release configs.
194type ReleaseConfigs struct {
195 // Ordered list of release config maps processed.
196 ReleaseConfigMaps []*ReleaseConfigMap
197
198 // Aliases
199 Aliases map[string]*string
200
201 // Dictionary of flag_name:FlagDeclaration, with no overrides applied.
202 FlagArtifacts FlagArtifacts
203
204 // Dictionary of name:ReleaseConfig
205 ReleaseConfigs map[string]*ReleaseConfig
206
207 // Generated release configs
208 Artifact release_config_proto.ReleaseConfigsArtifact
209
210 // The list of config directories used.
211 ConfigDirs []string
212
213 // A map from the config directory to its order in the list of config
214 // directories.
215 ConfigDirIndexes ReleaseConfigDirMap
216}
217
218func (src *FlagArtifact) Clone() *FlagArtifact {
219 value := &release_config_proto.Value{}
220 proto.Merge(value, src.Value)
221 return &FlagArtifact{
222 FlagDeclaration: src.FlagDeclaration,
223 Traces: src.Traces,
224 Value: value,
225 }
226}
227
228func (src FlagArtifacts) Clone() (dst FlagArtifacts) {
229 if dst == nil {
230 dst = make(FlagArtifacts)
231 }
232 for k, v := range src {
233 dst[k] = v.Clone()
234 }
235 return
236}
237
238func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) {
239 return &ReleaseConfig{Name: name, DeclarationIndex: index}
240}
241
242func ReleaseConfigsFactory() (c *ReleaseConfigs) {
243 return &ReleaseConfigs{
244 Aliases: make(map[string]*string),
245 FlagArtifacts: make(map[string]*FlagArtifact),
246 ReleaseConfigs: make(map[string]*ReleaseConfig),
247 ConfigDirs: []string{},
248 ConfigDirIndexes: make(ReleaseConfigDirMap),
249 }
250}
251
252func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) {
253 m = &ReleaseConfigMap{
254 path: protoPath,
255 ReleaseConfigContributions: make(map[string]*ReleaseConfigContribution),
256 }
257 if protoPath != "" {
258 LoadTextproto(protoPath, &m.proto)
259 }
260 return m
261}
262
263func FlagDeclarationFactory(protoPath string) (fd *release_config_proto.FlagDeclaration) {
264 fd = &release_config_proto.FlagDeclaration{}
265 if protoPath != "" {
266 LoadTextproto(protoPath, fd)
267 }
268 return fd
269}
270
271func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error {
272 m := ReleaseConfigMapFactory(path)
LaMont Jones1eccbf22024-04-08 09:09:35 -0700273 if m.proto.DefaultContainer == nil {
274 return fmt.Errorf("Release config map %s lacks default_container", path)
275 }
276 dir := filepath.Dir(path)
277 // Record any aliases, checking for duplicates.
278 for _, alias := range m.proto.Aliases {
279 name := *alias.Name
280 oldTarget, ok := configs.Aliases[name]
281 if ok {
282 if *oldTarget != *alias.Target {
283 return fmt.Errorf("Conflicting alias declarations: %s vs %s",
284 *oldTarget, *alias.Target)
285 }
286 }
287 configs.Aliases[name] = alias.Target
288 }
289 var err error
290 err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error {
291 flagDeclaration := FlagDeclarationFactory(path)
292 // Container must be specified.
293 if flagDeclaration.Container == nil {
294 flagDeclaration.Container = m.proto.DefaultContainer
295 }
LaMont Jonese6f54682024-04-10 16:15:58 -0700296 // TODO: once we have namespaces initialized, we can throw an error here.
297 if flagDeclaration.Namespace == nil {
298 flagDeclaration.Namespace = proto.String("android_UNKNOWN")
LaMont Jones1eccbf22024-04-08 09:09:35 -0700299 }
LaMont Jonese6f54682024-04-10 16:15:58 -0700300 // If the input didn't specify a value, create one (== UnspecifiedValue).
LaMont Jones1eccbf22024-04-08 09:09:35 -0700301 if flagDeclaration.Value == nil {
LaMont Jonese6f54682024-04-10 16:15:58 -0700302 flagDeclaration.Value = &release_config_proto.Value{Val: &release_config_proto.Value_UnspecifiedValue{false}}
LaMont Jones1eccbf22024-04-08 09:09:35 -0700303 }
304 m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
305 name := *flagDeclaration.Name
306 if def, ok := configs.FlagArtifacts[name]; !ok {
307 configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex}
308 } else if !proto.Equal(def.FlagDeclaration, flagDeclaration) {
309 return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name)
310 }
311 // Set the initial value in the flag artifact.
312 configs.FlagArtifacts[name].UpdateValue(
313 FlagValue{path: path, proto: release_config_proto.FlagValue{
314 Name: proto.String(name), Value: flagDeclaration.Value}})
315 return nil
316 })
317 if err != nil {
318 return err
319 }
320
321 err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
322 releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex}
323 LoadTextproto(path, &releaseConfigContribution.proto)
324 name := *releaseConfigContribution.proto.Name
325 if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) {
326 return fmt.Errorf("%s incorrectly declares release config %s", path, name)
327 }
328 if _, ok := configs.ReleaseConfigs[name]; !ok {
329 configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex)
330 }
331 config := configs.ReleaseConfigs[name]
332 config.InheritNames = append(config.InheritNames, releaseConfigContribution.proto.Inherits...)
333
334 // Only walk flag_values/{RELEASE} for defined releases.
335 err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error {
336 flagValue := FlagValueFactory(path)
337 if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) {
338 return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name)
339 }
340 releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue)
341 return nil
342 })
343 if err2 != nil {
344 return err2
345 }
346 m.ReleaseConfigContributions[name] = releaseConfigContribution
347 config.Contributions = append(config.Contributions, releaseConfigContribution)
348 return nil
349 })
350 if err != nil {
351 return err
352 }
353 configs.ReleaseConfigMaps = append(configs.ReleaseConfigMaps, m)
354 return nil
355}
356
357func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, error) {
358 trace := []string{name}
359 for target, ok := configs.Aliases[name]; ok; target, ok = configs.Aliases[name] {
360 name = *target
361 trace = append(trace, name)
362 }
363 if config, ok := configs.ReleaseConfigs[name]; ok {
364 return config, nil
365 }
366 return nil, fmt.Errorf("Missing config %s. Trace=%v", name, trace)
367}
368
369func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error {
370 outFile := filepath.Join(outDir, "release_config.mk")
371 makeVars := make(map[string]string)
372 config, err := configs.GetReleaseConfig(targetRelease)
373 if err != nil {
374 return err
375 }
376 // Sort the flags by name first.
377 names := []string{}
378 for k, _ := range config.FlagArtifacts {
379 names = append(names, k)
380 }
381 slices.SortFunc(names, func(a, b string) int {
382 return cmp.Compare(a, b)
383 })
384 partitions := make(map[string][]string)
385
386 vNames := []string{}
387 addVar := func(name, suffix, value string) {
388 fullName := fmt.Sprintf("_ALL_RELEASE_FLAGS.%s.%s", name, suffix)
389 vNames = append(vNames, fullName)
390 makeVars[fullName] = value
391 }
392
393 for _, name := range names {
394 flag := config.FlagArtifacts[name]
395 decl := flag.FlagDeclaration
396
397 // cName := strings.ToLower(release_config_proto.Container_name[decl.GetContainer()])
398 cName := strings.ToLower(decl.Container.String())
399 if cName == strings.ToLower(release_config_proto.Container_ALL.String()) {
400 partitions["product"] = append(partitions["product"], name)
401 partitions["system"] = append(partitions["system"], name)
402 partitions["system_ext"] = append(partitions["system_ext"], name)
403 partitions["vendor"] = append(partitions["vendor"], name)
404 } else {
405 partitions[cName] = append(partitions[cName], name)
406 }
407 value := MarshalValue(flag.Value)
408 makeVars[name] = value
409 addVar(name, "PARTITIONS", cName)
410 addVar(name, "DEFAULT", MarshalValue(decl.Value))
411 addVar(name, "VALUE", value)
412 addVar(name, "DECLARED_IN", *flag.Traces[0].Source)
413 addVar(name, "SET_IN", *flag.Traces[len(flag.Traces)-1].Source)
LaMont Jonese6f54682024-04-10 16:15:58 -0700414 addVar(name, "NAMESPACE", *decl.Namespace)
LaMont Jones1eccbf22024-04-08 09:09:35 -0700415 }
416 pNames := []string{}
417 for k, _ := range partitions {
418 pNames = append(pNames, k)
419 }
420 slices.SortFunc(pNames, func(a, b string) int {
421 return cmp.Compare(a, b)
422 })
423
424 // Now sort the make variables, and output them.
425 slices.SortFunc(vNames, func(a, b string) int {
426 return cmp.Compare(a, b)
427 })
428
429 // Write the flags as:
430 // _ALL_RELELASE_FLAGS
431 // _ALL_RELEASE_FLAGS.PARTITIONS.*
432 // all _ALL_RELEASE_FLAGS.*, sorted by name
433 // Final flag values, sorted by name.
434 data := fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
435 for _, pName := range pNames {
436 data += fmt.Sprintf("_ALL_RELEASE_FLAGS.PARTITIONS.%s :=$= %s\n", pName, strings.Join(partitions[pName], " "))
437 }
438 for _, vName := range vNames {
439 data += fmt.Sprintf("%s :=$= %s\n", vName, makeVars[vName])
440 }
441 data += "\n\n# Values for all build flags\n"
442 data += fmt.Sprintf("RELEASE_ACONFIG_VALUE_SETS :=$= %s\n",
443 strings.Join(config.ReleaseConfigArtifact.AconfigValueSets, " "))
444 for _, name := range names {
445 data += fmt.Sprintf("%s :=$= %s\n", name, makeVars[name])
446 }
447 return os.WriteFile(outFile, []byte(data), 0644)
448}
449
450func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) error {
451 otherNames := make(map[string][]string)
452 for aliasName, aliasTarget := range configs.Aliases {
453 if _, ok := configs.ReleaseConfigs[aliasName]; ok {
454 return fmt.Errorf("Alias %s is a declared release config", aliasName)
455 }
456 if _, ok := configs.ReleaseConfigs[*aliasTarget]; !ok {
457 if _, ok2 := configs.Aliases[*aliasTarget]; !ok2 {
458 return fmt.Errorf("Alias %s points to non-existing config %s", aliasName, *aliasTarget)
459 }
460 }
461 otherNames[*aliasTarget] = append(otherNames[*aliasTarget], aliasName)
462 }
463 for name, aliases := range otherNames {
464 configs.ReleaseConfigs[name].OtherNames = aliases
465 }
466
467 for _, config := range configs.ReleaseConfigs {
468 err := config.GenerateReleaseConfig(configs)
469 if err != nil {
470 return err
471 }
472 }
473
474 releaseConfig, err := configs.GetReleaseConfig(targetRelease)
475 if err != nil {
476 return err
477 }
478 configs.Artifact = release_config_proto.ReleaseConfigsArtifact{
479 ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
480 OtherReleaseConfigs: func() []*release_config_proto.ReleaseConfigArtifact {
481 orc := []*release_config_proto.ReleaseConfigArtifact{}
482 for name, config := range configs.ReleaseConfigs {
483 if name != releaseConfig.Name {
484 orc = append(orc, config.ReleaseConfigArtifact)
485 }
486 }
487 return orc
488 }(),
489 }
490 return nil
491}
492
493func MarshalValue(value *release_config_proto.Value) string {
494 switch val := value.Val.(type) {
495 case *release_config_proto.Value_UnspecifiedValue:
496 // Value was never set.
497 return ""
498 case *release_config_proto.Value_StringValue:
499 return val.StringValue
500 case *release_config_proto.Value_BoolValue:
501 if val.BoolValue {
502 return "true"
503 }
504 // False ==> empty string
505 return ""
506 case *release_config_proto.Value_Obsolete:
507 return " #OBSOLETE"
508 default:
509 // Flagged as error elsewhere, so return empty string here.
510 return ""
511 }
512}
513
514func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error {
515 name := *flagValue.proto.Name
516 fa.Traces = append(fa.Traces, &release_config_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
517 if fa.Value.GetObsolete() {
518 return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces)
519 }
520 switch val := flagValue.proto.Value.Val.(type) {
521 case *release_config_proto.Value_StringValue:
522 fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_StringValue{val.StringValue}}
523 case *release_config_proto.Value_BoolValue:
524 fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_BoolValue{val.BoolValue}}
525 case *release_config_proto.Value_Obsolete:
526 if !val.Obsolete {
527 return fmt.Errorf("%s: Cannot set obsolete=false. Trace=%v", name, fa.Traces)
528 }
529 fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_Obsolete{true}}
530 default:
531 return fmt.Errorf("Invalid type for flag_value: %T. Trace=%v", val, fa.Traces)
532 }
533 return nil
534}
535
536func (fa *FlagArtifact) Marshal() (*release_config_proto.FlagArtifact, error) {
537 return &release_config_proto.FlagArtifact{
538 FlagDeclaration: fa.FlagDeclaration,
539 Value: fa.Value,
540 Traces: fa.Traces,
541 }, nil
542}
543
544func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error {
545 if config.ReleaseConfigArtifact != nil {
546 return nil
547 }
548 if config.compileInProgress {
549 return fmt.Errorf("Loop detected for release config %s", config.Name)
550 }
551 config.compileInProgress = true
552
553 // Generate any configs we need to inherit. This will detect loops in
554 // the config.
555 contributionsToApply := []*ReleaseConfigContribution{}
556 myInherits := []string{}
557 myInheritsSet := make(map[string]bool)
558 for _, inherit := range config.InheritNames {
559 if _, ok := myInheritsSet[inherit]; ok {
560 continue
561 }
562 myInherits = append(myInherits, inherit)
563 myInheritsSet[inherit] = true
564 iConfig, err := configs.GetReleaseConfig(inherit)
565 if err != nil {
566 return err
567 }
568 iConfig.GenerateReleaseConfig(configs)
569 contributionsToApply = append(contributionsToApply, iConfig.Contributions...)
570 }
571 contributionsToApply = append(contributionsToApply, config.Contributions...)
572
573 myAconfigValueSets := []string{}
574 myFlags := configs.FlagArtifacts.Clone()
575 myDirsMap := make(map[int]bool)
576 for _, contrib := range contributionsToApply {
577 myAconfigValueSets = append(myAconfigValueSets, contrib.proto.AconfigValueSets...)
578 myDirsMap[contrib.DeclarationIndex] = true
579 for _, value := range contrib.FlagValues {
580 fa, ok := myFlags[*value.proto.Name]
581 if !ok {
582 return fmt.Errorf("Setting value for undefined flag %s in %s\n", *value.proto.Name, value.path)
583 }
584 myDirsMap[fa.DeclarationIndex] = true
585 if fa.DeclarationIndex > contrib.DeclarationIndex {
586 // Setting location is to the left of declaration.
587 return fmt.Errorf("Setting value for flag %s not allowed in %s\n", *value.proto.Name, value.path)
588 }
589 if err := fa.UpdateValue(*value); err != nil {
590 return err
591 }
592 }
593 }
594
595 directories := []string{}
596 for idx, confDir := range configs.ConfigDirs {
597 if _, ok := myDirsMap[idx]; ok {
598 directories = append(directories, confDir)
599 }
600 }
601
602 config.FlagArtifacts = myFlags
603 config.ReleaseConfigArtifact = &release_config_proto.ReleaseConfigArtifact{
604 Name: proto.String(config.Name),
605 OtherNames: config.OtherNames,
606 FlagArtifacts: func() []*release_config_proto.FlagArtifact {
607 ret := []*release_config_proto.FlagArtifact{}
608 for _, flag := range myFlags {
609 ret = append(ret, &release_config_proto.FlagArtifact{
610 FlagDeclaration: flag.FlagDeclaration,
611 Traces: flag.Traces,
612 Value: flag.Value,
613 })
614 }
615 return ret
616 }(),
617 AconfigValueSets: myAconfigValueSets,
618 Inherits: myInherits,
619 Directories: directories,
620 }
621
622 config.compileInProgress = false
623 return nil
624}
625
LaMont Jonese6f54682024-04-10 16:15:58 -0700626func GetDefaultOutDir() string {
LaMont Jones1eccbf22024-04-08 09:09:35 -0700627 outEnv := os.Getenv("OUT_DIR")
628 if outEnv == "" {
629 outEnv = "out"
630 }
LaMont Jonese6f54682024-04-10 16:15:58 -0700631 return filepath.Join(outEnv, "soong", "release-config")
632}
633func GetDefaultMapPaths() StringList {
LaMont Jones1eccbf22024-04-08 09:09:35 -0700634 var defaultMapPaths StringList
635 defaultLocations := StringList{
636 "build/release/release_config_map.textproto",
637 "vendor/google_shared/build/release/release_config_map.textproto",
638 "vendor/google/release/release_config_map.textproto",
639 }
640 for _, path := range defaultLocations {
641 if _, err := os.Stat(path); err == nil {
642 defaultMapPaths = append(defaultMapPaths, path)
643 }
644 }
645 prodMaps := os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS")
646 if prodMaps != "" {
647 defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...)
648 }
LaMont Jonese6f54682024-04-10 16:15:58 -0700649 return defaultMapPaths
650}
LaMont Jones1eccbf22024-04-08 09:09:35 -0700651
LaMont Jonese6f54682024-04-10 16:15:58 -0700652func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string) (*ReleaseConfigs, error) {
653 var err error
LaMont Jones1eccbf22024-04-08 09:09:35 -0700654 configs := ReleaseConfigsFactory()
655 for idx, releaseConfigMapPath := range releaseConfigMapPaths {
656 // Maintain an ordered list of release config directories.
657 configDir := filepath.Dir(releaseConfigMapPath)
658 configs.ConfigDirIndexes[configDir] = idx
659 configs.ConfigDirs = append(configs.ConfigDirs, configDir)
LaMont Jonese6f54682024-04-10 16:15:58 -0700660 err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx)
LaMont Jones1eccbf22024-04-08 09:09:35 -0700661 if err != nil {
LaMont Jonese6f54682024-04-10 16:15:58 -0700662 return nil, err
LaMont Jones1eccbf22024-04-08 09:09:35 -0700663 }
664 }
665
666 // Now that we have all of the release config maps, can meld them and generate the artifacts.
LaMont Jonese6f54682024-04-10 16:15:58 -0700667 err = configs.GenerateReleaseConfigs(targetRelease)
668 return configs, err
669}
670
671func main() {
672 var targetRelease string
673 var outputDir string
674
675 flag.BoolVar(&verboseFlag, "debug", false, "print debugging information")
676 flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated")
677 flag.StringVar(&targetRelease, "release", "trunk_staging", "TARGET_RELEASE for this build")
678 flag.StringVar(&outputDir, "out_dir", GetDefaultOutDir(), "basepath for the output. Multiple formats are created")
679 flag.Parse()
680
681 if len(releaseConfigMapPaths) == 0 {
682 releaseConfigMapPaths = GetDefaultMapPaths()
683 if len(releaseConfigMapPaths) == 0 {
684 panic(fmt.Errorf("No maps found"))
685 }
686 fmt.Printf("No --map argument provided. Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map "))
687 }
688
689 configs, err := ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease)
LaMont Jones1eccbf22024-04-08 09:09:35 -0700690 if err != nil {
691 panic(err)
692 }
693 err = os.MkdirAll(outputDir, 0775)
694 if err != nil {
695 panic(err)
696 }
697 err = configs.DumpMakefile(outputDir, targetRelease)
698 if err != nil {
699 panic(err)
700 }
701 DumpProtos(outputDir, &configs.Artifact)
702}