xref: /aosp_15_r20/build/soong/cmd/release_config/release_config_contributions/main.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1package main
2
3import (
4	"flag"
5	"fmt"
6	"os"
7	"slices"
8	"strings"
9
10	rc_lib "android/soong/cmd/release_config/release_config_lib"
11	rc_proto "android/soong/cmd/release_config/release_config_proto"
12)
13
14type Flags struct {
15	// The path to the top of the workspace.  Default: ".".
16	top string
17
18	// Output file.
19	output string
20
21	// Format for output file
22	format string
23
24	// List of release config directories to process.
25	dirs rc_lib.StringList
26
27	// Disable warning messages
28	quiet bool
29
30	// Panic on errors.
31	debug bool
32}
33
34func sortDirectories(dirList []string) {
35	order := func(dir string) int {
36		switch {
37		// These three are always in this order.
38		case dir == "build/release":
39			return 1
40		case dir == "vendor/google_shared/build/release":
41			return 2
42		case dir == "vendor/google/release":
43			return 3
44		// Keep their subdirs in the same order.
45		case strings.HasPrefix(dir, "build/release/"):
46			return 21
47		case strings.HasPrefix(dir, "vendor/google_shared/build/release/"):
48			return 22
49		case strings.HasPrefix(dir, "vendor/google/release/"):
50			return 23
51		// Everything else sorts by directory path.
52		default:
53			return 99
54		}
55	}
56
57	slices.SortFunc(dirList, func(a, b string) int {
58		aOrder, bOrder := order(a), order(b)
59		if aOrder != bOrder {
60			return aOrder - bOrder
61		}
62		return strings.Compare(a, b)
63	})
64}
65
66func main() {
67	var flags Flags
68	topDir, err := rc_lib.GetTopDir()
69
70	// Handle the common arguments
71	flag.StringVar(&flags.top, "top", topDir, "path to top of workspace")
72	flag.Var(&flags.dirs, "dir", "path to a release config contribution directory. May be repeated")
73	flag.StringVar(&flags.format, "format", "pb", "output file format")
74	flag.StringVar(&flags.output, "output", "release_config_contributions.pb", "output file")
75	flag.BoolVar(&flags.debug, "debug", false, "turn on debugging output for errors")
76	flag.BoolVar(&flags.quiet, "quiet", false, "disable warning messages")
77	flag.Parse()
78
79	errorExit := func(err error) {
80		if flags.debug {
81			panic(err)
82		}
83		fmt.Fprintf(os.Stderr, "%s\n", err)
84		os.Exit(1)
85	}
86
87	if flags.quiet {
88		rc_lib.DisableWarnings()
89	}
90
91	if err = os.Chdir(flags.top); err != nil {
92		errorExit(err)
93	}
94
95	contributingDirsMap := make(map[string][]string)
96	for _, dir := range flags.dirs {
97		contributions, err := rc_lib.EnumerateReleaseConfigs(dir)
98		if err != nil {
99			errorExit(err)
100		}
101		for _, name := range contributions {
102			contributingDirsMap[name] = append(contributingDirsMap[name], dir)
103		}
104	}
105
106	releaseConfigNames := []string{}
107	for name := range contributingDirsMap {
108		releaseConfigNames = append(releaseConfigNames, name)
109	}
110	slices.Sort(releaseConfigNames)
111
112	message := &rc_proto.ReleaseConfigContributionsArtifacts{
113		ReleaseConfigContributionsArtifactList: []*rc_proto.ReleaseConfigContributionsArtifact{},
114	}
115	for _, name := range releaseConfigNames {
116		dirs := contributingDirsMap[name]
117		sortDirectories(dirs)
118		message.ReleaseConfigContributionsArtifactList = append(
119			message.ReleaseConfigContributionsArtifactList,
120			&rc_proto.ReleaseConfigContributionsArtifact{
121				Name:                    &name,
122				ContributingDirectories: dirs,
123			})
124	}
125
126	err = rc_lib.WriteFormattedMessage(flags.output, flags.format, message)
127	if err != nil {
128		errorExit(err)
129	}
130}
131