blob: 3bb6b3dfe81c7c83e7f25a4f4a266b54d2b7d0bc [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)
273 if m.proto.Origin == nil || *m.proto.Origin == "" {
274 return fmt.Errorf("Release config map %s lacks origin", path)
275 }
276 if m.proto.DefaultContainer == nil {
277 return fmt.Errorf("Release config map %s lacks default_container", path)
278 }
279 dir := filepath.Dir(path)
280 // Record any aliases, checking for duplicates.
281 for _, alias := range m.proto.Aliases {
282 name := *alias.Name
283 oldTarget, ok := configs.Aliases[name]
284 if ok {
285 if *oldTarget != *alias.Target {
286 return fmt.Errorf("Conflicting alias declarations: %s vs %s",
287 *oldTarget, *alias.Target)
288 }
289 }
290 configs.Aliases[name] = alias.Target
291 }
292 var err error
293 err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error {
294 flagDeclaration := FlagDeclarationFactory(path)
295 // Container must be specified.
296 if flagDeclaration.Container == nil {
297 flagDeclaration.Container = m.proto.DefaultContainer
298 }
299 // TODO: drop flag_declaration.origin from the proto.
300 if flagDeclaration.Origin == nil {
301 flagDeclaration.Origin = m.proto.Origin
302 }
303 // There is always a default value.
304 if flagDeclaration.Value == nil {
305 flagDeclaration.Value = &release_config_proto.Value{Val: &release_config_proto.Value_UnspecifiedValue{true}}
306 }
307 m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
308 name := *flagDeclaration.Name
309 if def, ok := configs.FlagArtifacts[name]; !ok {
310 configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex}
311 } else if !proto.Equal(def.FlagDeclaration, flagDeclaration) {
312 return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name)
313 }
314 // Set the initial value in the flag artifact.
315 configs.FlagArtifacts[name].UpdateValue(
316 FlagValue{path: path, proto: release_config_proto.FlagValue{
317 Name: proto.String(name), Value: flagDeclaration.Value}})
318 return nil
319 })
320 if err != nil {
321 return err
322 }
323
324 err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
325 releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex}
326 LoadTextproto(path, &releaseConfigContribution.proto)
327 name := *releaseConfigContribution.proto.Name
328 if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) {
329 return fmt.Errorf("%s incorrectly declares release config %s", path, name)
330 }
331 if _, ok := configs.ReleaseConfigs[name]; !ok {
332 configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex)
333 }
334 config := configs.ReleaseConfigs[name]
335 config.InheritNames = append(config.InheritNames, releaseConfigContribution.proto.Inherits...)
336
337 // Only walk flag_values/{RELEASE} for defined releases.
338 err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error {
339 flagValue := FlagValueFactory(path)
340 if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) {
341 return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name)
342 }
343 releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue)
344 return nil
345 })
346 if err2 != nil {
347 return err2
348 }
349 m.ReleaseConfigContributions[name] = releaseConfigContribution
350 config.Contributions = append(config.Contributions, releaseConfigContribution)
351 return nil
352 })
353 if err != nil {
354 return err
355 }
356 configs.ReleaseConfigMaps = append(configs.ReleaseConfigMaps, m)
357 return nil
358}
359
360func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, error) {
361 trace := []string{name}
362 for target, ok := configs.Aliases[name]; ok; target, ok = configs.Aliases[name] {
363 name = *target
364 trace = append(trace, name)
365 }
366 if config, ok := configs.ReleaseConfigs[name]; ok {
367 return config, nil
368 }
369 return nil, fmt.Errorf("Missing config %s. Trace=%v", name, trace)
370}
371
372func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error {
373 outFile := filepath.Join(outDir, "release_config.mk")
374 makeVars := make(map[string]string)
375 config, err := configs.GetReleaseConfig(targetRelease)
376 if err != nil {
377 return err
378 }
379 // Sort the flags by name first.
380 names := []string{}
381 for k, _ := range config.FlagArtifacts {
382 names = append(names, k)
383 }
384 slices.SortFunc(names, func(a, b string) int {
385 return cmp.Compare(a, b)
386 })
387 partitions := make(map[string][]string)
388
389 vNames := []string{}
390 addVar := func(name, suffix, value string) {
391 fullName := fmt.Sprintf("_ALL_RELEASE_FLAGS.%s.%s", name, suffix)
392 vNames = append(vNames, fullName)
393 makeVars[fullName] = value
394 }
395
396 for _, name := range names {
397 flag := config.FlagArtifacts[name]
398 decl := flag.FlagDeclaration
399
400 // cName := strings.ToLower(release_config_proto.Container_name[decl.GetContainer()])
401 cName := strings.ToLower(decl.Container.String())
402 if cName == strings.ToLower(release_config_proto.Container_ALL.String()) {
403 partitions["product"] = append(partitions["product"], name)
404 partitions["system"] = append(partitions["system"], name)
405 partitions["system_ext"] = append(partitions["system_ext"], name)
406 partitions["vendor"] = append(partitions["vendor"], name)
407 } else {
408 partitions[cName] = append(partitions[cName], name)
409 }
410 value := MarshalValue(flag.Value)
411 makeVars[name] = value
412 addVar(name, "PARTITIONS", cName)
413 addVar(name, "DEFAULT", MarshalValue(decl.Value))
414 addVar(name, "VALUE", value)
415 addVar(name, "DECLARED_IN", *flag.Traces[0].Source)
416 addVar(name, "SET_IN", *flag.Traces[len(flag.Traces)-1].Source)
417 addVar(name, "ORIGIN", *decl.Origin)
418 }
419 pNames := []string{}
420 for k, _ := range partitions {
421 pNames = append(pNames, k)
422 }
423 slices.SortFunc(pNames, func(a, b string) int {
424 return cmp.Compare(a, b)
425 })
426
427 // Now sort the make variables, and output them.
428 slices.SortFunc(vNames, func(a, b string) int {
429 return cmp.Compare(a, b)
430 })
431
432 // Write the flags as:
433 // _ALL_RELELASE_FLAGS
434 // _ALL_RELEASE_FLAGS.PARTITIONS.*
435 // all _ALL_RELEASE_FLAGS.*, sorted by name
436 // Final flag values, sorted by name.
437 data := fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
438 for _, pName := range pNames {
439 data += fmt.Sprintf("_ALL_RELEASE_FLAGS.PARTITIONS.%s :=$= %s\n", pName, strings.Join(partitions[pName], " "))
440 }
441 for _, vName := range vNames {
442 data += fmt.Sprintf("%s :=$= %s\n", vName, makeVars[vName])
443 }
444 data += "\n\n# Values for all build flags\n"
445 data += fmt.Sprintf("RELEASE_ACONFIG_VALUE_SETS :=$= %s\n",
446 strings.Join(config.ReleaseConfigArtifact.AconfigValueSets, " "))
447 for _, name := range names {
448 data += fmt.Sprintf("%s :=$= %s\n", name, makeVars[name])
449 }
450 return os.WriteFile(outFile, []byte(data), 0644)
451}
452
453func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) error {
454 otherNames := make(map[string][]string)
455 for aliasName, aliasTarget := range configs.Aliases {
456 if _, ok := configs.ReleaseConfigs[aliasName]; ok {
457 return fmt.Errorf("Alias %s is a declared release config", aliasName)
458 }
459 if _, ok := configs.ReleaseConfigs[*aliasTarget]; !ok {
460 if _, ok2 := configs.Aliases[*aliasTarget]; !ok2 {
461 return fmt.Errorf("Alias %s points to non-existing config %s", aliasName, *aliasTarget)
462 }
463 }
464 otherNames[*aliasTarget] = append(otherNames[*aliasTarget], aliasName)
465 }
466 for name, aliases := range otherNames {
467 configs.ReleaseConfigs[name].OtherNames = aliases
468 }
469
470 for _, config := range configs.ReleaseConfigs {
471 err := config.GenerateReleaseConfig(configs)
472 if err != nil {
473 return err
474 }
475 }
476
477 releaseConfig, err := configs.GetReleaseConfig(targetRelease)
478 if err != nil {
479 return err
480 }
481 configs.Artifact = release_config_proto.ReleaseConfigsArtifact{
482 ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
483 OtherReleaseConfigs: func() []*release_config_proto.ReleaseConfigArtifact {
484 orc := []*release_config_proto.ReleaseConfigArtifact{}
485 for name, config := range configs.ReleaseConfigs {
486 if name != releaseConfig.Name {
487 orc = append(orc, config.ReleaseConfigArtifact)
488 }
489 }
490 return orc
491 }(),
492 }
493 return nil
494}
495
496func MarshalValue(value *release_config_proto.Value) string {
497 switch val := value.Val.(type) {
498 case *release_config_proto.Value_UnspecifiedValue:
499 // Value was never set.
500 return ""
501 case *release_config_proto.Value_StringValue:
502 return val.StringValue
503 case *release_config_proto.Value_BoolValue:
504 if val.BoolValue {
505 return "true"
506 }
507 // False ==> empty string
508 return ""
509 case *release_config_proto.Value_Obsolete:
510 return " #OBSOLETE"
511 default:
512 // Flagged as error elsewhere, so return empty string here.
513 return ""
514 }
515}
516
517func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error {
518 name := *flagValue.proto.Name
519 fa.Traces = append(fa.Traces, &release_config_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
520 if fa.Value.GetObsolete() {
521 return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces)
522 }
523 switch val := flagValue.proto.Value.Val.(type) {
524 case *release_config_proto.Value_StringValue:
525 fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_StringValue{val.StringValue}}
526 case *release_config_proto.Value_BoolValue:
527 fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_BoolValue{val.BoolValue}}
528 case *release_config_proto.Value_Obsolete:
529 if !val.Obsolete {
530 return fmt.Errorf("%s: Cannot set obsolete=false. Trace=%v", name, fa.Traces)
531 }
532 fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_Obsolete{true}}
533 default:
534 return fmt.Errorf("Invalid type for flag_value: %T. Trace=%v", val, fa.Traces)
535 }
536 return nil
537}
538
539func (fa *FlagArtifact) Marshal() (*release_config_proto.FlagArtifact, error) {
540 return &release_config_proto.FlagArtifact{
541 FlagDeclaration: fa.FlagDeclaration,
542 Value: fa.Value,
543 Traces: fa.Traces,
544 }, nil
545}
546
547func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error {
548 if config.ReleaseConfigArtifact != nil {
549 return nil
550 }
551 if config.compileInProgress {
552 return fmt.Errorf("Loop detected for release config %s", config.Name)
553 }
554 config.compileInProgress = true
555
556 // Generate any configs we need to inherit. This will detect loops in
557 // the config.
558 contributionsToApply := []*ReleaseConfigContribution{}
559 myInherits := []string{}
560 myInheritsSet := make(map[string]bool)
561 for _, inherit := range config.InheritNames {
562 if _, ok := myInheritsSet[inherit]; ok {
563 continue
564 }
565 myInherits = append(myInherits, inherit)
566 myInheritsSet[inherit] = true
567 iConfig, err := configs.GetReleaseConfig(inherit)
568 if err != nil {
569 return err
570 }
571 iConfig.GenerateReleaseConfig(configs)
572 contributionsToApply = append(contributionsToApply, iConfig.Contributions...)
573 }
574 contributionsToApply = append(contributionsToApply, config.Contributions...)
575
576 myAconfigValueSets := []string{}
577 myFlags := configs.FlagArtifacts.Clone()
578 myDirsMap := make(map[int]bool)
579 for _, contrib := range contributionsToApply {
580 myAconfigValueSets = append(myAconfigValueSets, contrib.proto.AconfigValueSets...)
581 myDirsMap[contrib.DeclarationIndex] = true
582 for _, value := range contrib.FlagValues {
583 fa, ok := myFlags[*value.proto.Name]
584 if !ok {
585 return fmt.Errorf("Setting value for undefined flag %s in %s\n", *value.proto.Name, value.path)
586 }
587 myDirsMap[fa.DeclarationIndex] = true
588 if fa.DeclarationIndex > contrib.DeclarationIndex {
589 // Setting location is to the left of declaration.
590 return fmt.Errorf("Setting value for flag %s not allowed in %s\n", *value.proto.Name, value.path)
591 }
592 if err := fa.UpdateValue(*value); err != nil {
593 return err
594 }
595 }
596 }
597
598 directories := []string{}
599 for idx, confDir := range configs.ConfigDirs {
600 if _, ok := myDirsMap[idx]; ok {
601 directories = append(directories, confDir)
602 }
603 }
604
605 config.FlagArtifacts = myFlags
606 config.ReleaseConfigArtifact = &release_config_proto.ReleaseConfigArtifact{
607 Name: proto.String(config.Name),
608 OtherNames: config.OtherNames,
609 FlagArtifacts: func() []*release_config_proto.FlagArtifact {
610 ret := []*release_config_proto.FlagArtifact{}
611 for _, flag := range myFlags {
612 ret = append(ret, &release_config_proto.FlagArtifact{
613 FlagDeclaration: flag.FlagDeclaration,
614 Traces: flag.Traces,
615 Value: flag.Value,
616 })
617 }
618 return ret
619 }(),
620 AconfigValueSets: myAconfigValueSets,
621 Inherits: myInherits,
622 Directories: directories,
623 }
624
625 config.compileInProgress = false
626 return nil
627}
628
629func main() {
630 var targetRelease string
631 var outputDir string
632
633 outEnv := os.Getenv("OUT_DIR")
634 if outEnv == "" {
635 outEnv = "out"
636 }
637 defaultOutputDir := filepath.Join(outEnv, "soong", "release-config")
638 var defaultMapPaths StringList
639 defaultLocations := StringList{
640 "build/release/release_config_map.textproto",
641 "vendor/google_shared/build/release/release_config_map.textproto",
642 "vendor/google/release/release_config_map.textproto",
643 }
644 for _, path := range defaultLocations {
645 if _, err := os.Stat(path); err == nil {
646 defaultMapPaths = append(defaultMapPaths, path)
647 }
648 }
649 prodMaps := os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS")
650 if prodMaps != "" {
651 defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...)
652 }
653
654 flag.BoolVar(&verboseFlag, "debug", false, "print debugging information")
655 flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated")
656 flag.StringVar(&targetRelease, "release", "trunk_staging", "TARGET_RELEASE for this build")
657 flag.StringVar(&outputDir, "out_dir", defaultOutputDir, "basepath for the output. Multiple formats are created")
658 flag.Parse()
659
660 if len(releaseConfigMapPaths) == 0 {
661 releaseConfigMapPaths = defaultMapPaths
662 fmt.Printf("No --map argument provided. Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map "))
663 }
664
665 configs := ReleaseConfigsFactory()
666 for idx, releaseConfigMapPath := range releaseConfigMapPaths {
667 // Maintain an ordered list of release config directories.
668 configDir := filepath.Dir(releaseConfigMapPath)
669 configs.ConfigDirIndexes[configDir] = idx
670 configs.ConfigDirs = append(configs.ConfigDirs, configDir)
671 err := configs.LoadReleaseConfigMap(releaseConfigMapPath, idx)
672 if err != nil {
673 panic(err)
674 }
675 }
676
677 // Now that we have all of the release config maps, can meld them and generate the artifacts.
678 err := configs.GenerateReleaseConfigs(targetRelease)
679 if err != nil {
680 panic(err)
681 }
682 err = os.MkdirAll(outputDir, 0775)
683 if err != nil {
684 panic(err)
685 }
686 err = configs.DumpMakefile(outputDir, targetRelease)
687 if err != nil {
688 panic(err)
689 }
690 DumpProtos(outputDir, &configs.Artifact)
691}