blob: 0c433a6cbc5f3287bde4e7f1aa21b1b405f0ff5e [file] [log] [blame]
Ronald Braunstein73b08ff2023-12-19 10:24:47 -08001package android
2
3import (
4 "android/soong/android/team_proto"
5 "path/filepath"
6
7 "google.golang.org/protobuf/proto"
8)
9
10const ownershipDirectory = "ownership"
11const allTeamsFile = "all_teams.pb"
12
13func AllTeamsFactory() Singleton {
14 return &allTeamsSingleton{}
15}
16
17func init() {
18 registerAllTeamBuildComponents(InitRegistrationContext)
19}
20
21func registerAllTeamBuildComponents(ctx RegistrationContext) {
22 ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
23}
24
25// For each module, list the team or the bpFile the module is defined in.
Ronald Braunsteinc5603092024-03-27 06:46:47 -070026type moduleTeamAndTestInfo struct {
27 // Name field from bp file for the team
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080028 teamName string
Ronald Braunsteinc5603092024-03-27 06:46:47 -070029 // Blueprint file the module is located in.
30 bpFile string
31 // Is this module only used by tests.
32 testOnly bool
33 // Is this a directly testable target by running the module directly
34 // or via tradefed.
35 topLevelTestTarget bool
36 // String name indicating the module, like `java_library` for reporting.
37 kind string
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080038}
39
40type allTeamsSingleton struct {
41 // Path where the collected metadata is stored after successful validation.
42 outputPath OutputPath
43
44 // Map of all package modules we visit during GenerateBuildActions
45 packages map[string]packageProperties
46 // Map of all team modules we visit during GenerateBuildActions
47 teams map[string]teamProperties
48 // Keeps track of team information or bp file for each module we visit.
Ronald Braunsteinc5603092024-03-27 06:46:47 -070049 teams_for_mods map[string]moduleTeamAndTestInfo
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080050}
51
52// See if there is a package module for the given bpFilePath with a team defined, if so return the team.
53// If not ascend up to the parent directory and do the same.
Ronald Braunsteinc5603092024-03-27 06:46:47 -070054func (t *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080055 // return the Default_team listed in the package if is there.
Ronald Braunsteinc5603092024-03-27 06:46:47 -070056 if p, ok := t.packages[bpFilePath]; ok {
57 if defaultTeam := p.Default_team; defaultTeam != nil {
58 return t.teams[*defaultTeam], true
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080059 }
60 }
61 // Strip a directory and go up.
62 // Does android/paths.go basePath,SourcePath help?
63 current, base := filepath.Split(bpFilePath)
64 current = filepath.Clean(current) // removes trailing slash, convert "" -> "."
65 parent, _ := filepath.Split(current)
66 if current == "." {
67 return teamProperties{}, false
68 }
Ronald Braunsteinc5603092024-03-27 06:46:47 -070069 return t.lookupDefaultTeam(filepath.Join(parent, base))
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080070}
71
Ronald Braunsteinc5603092024-03-27 06:46:47 -070072// Visit all modules and collect all teams and use WriteFileRuleVerbatim
73// to write it out.
74func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
75 t.packages = make(map[string]packageProperties)
76 t.teams = make(map[string]teamProperties)
77 t.teams_for_mods = make(map[string]moduleTeamAndTestInfo)
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080078
79 ctx.VisitAllModules(func(module Module) {
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080080 bpFile := ctx.BlueprintFile(module)
81
Ronald Braunsteinc5603092024-03-27 06:46:47 -070082 testModInfo := TestModuleInformation{}
83 if tmi, ok := SingletonModuleProvider(ctx, module, TestOnlyProviderKey); ok {
84 testModInfo = tmi
85 }
86
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080087 // Package Modules and Team Modules are stored in a map so we can look them up by name for
88 // modules without a team.
89 if pack, ok := module.(*packageModule); ok {
Ronald Braunsteinc5603092024-03-27 06:46:47 -070090 // Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in t context.
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080091 pkgKey := bpFile
Ronald Braunsteinc5603092024-03-27 06:46:47 -070092 t.packages[pkgKey] = pack.properties
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080093 return
94 }
95 if team, ok := module.(*teamModule); ok {
Ronald Braunsteinc5603092024-03-27 06:46:47 -070096 t.teams[team.Name()] = team.properties
Ronald Braunstein73b08ff2023-12-19 10:24:47 -080097 return
98 }
99
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700100 entry := moduleTeamAndTestInfo{
101 bpFile: bpFile,
102 testOnly: testModInfo.TestOnly,
103 topLevelTestTarget: testModInfo.TopLevelTarget,
104 kind: ctx.ModuleType(module),
105 teamName: module.base().Team(),
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800106 }
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700107 t.teams_for_mods[module.Name()] = entry
108
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800109 })
110
111 // Visit all modules again and lookup the team name in the package or parent package if the team
112 // isn't assignged at the module level.
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700113 allTeams := t.lookupTeamForAllModules()
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800114
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700115 t.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800116 data, err := proto.Marshal(allTeams)
117 if err != nil {
118 ctx.Errorf("Unable to marshal team data. %s", err)
119 }
120
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700121 WriteFileRuleVerbatim(ctx, t.outputPath, string(data))
122 ctx.Phony("all_teams", t.outputPath)
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800123}
124
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700125func (t *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
126 ctx.DistForGoal("all_teams", t.outputPath)
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800127}
128
129// Visit every (non-package, non-team) module and write out a proto containing
130// either the declared team data for that module or the package default team data for that module.
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700131func (t *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
132 teamsProto := make([]*team_proto.Team, len(t.teams_for_mods))
133 for i, moduleName := range SortedKeys(t.teams_for_mods) {
134 m, _ := t.teams_for_mods[moduleName]
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800135 teamName := m.teamName
136 var teamProperties teamProperties
137 found := false
138 if teamName != "" {
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700139 teamProperties, found = t.teams[teamName]
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800140 } else {
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700141 teamProperties, found = t.lookupDefaultTeam(m.bpFile)
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800142 }
143
144 trendy_team_id := ""
145 if found {
146 trendy_team_id = *teamProperties.Trendy_team_id
147 }
148
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800149 teamData := new(team_proto.Team)
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700150 *teamData = team_proto.Team{
151 TargetName: proto.String(moduleName),
152 Path: proto.String(m.bpFile),
153 TestOnly: proto.Bool(m.testOnly),
154 TopLevelTarget: proto.Bool(m.topLevelTestTarget),
155 Kind: proto.String(m.kind),
156 }
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800157 if trendy_team_id != "" {
Ronald Braunsteinc5603092024-03-27 06:46:47 -0700158 teamData.TrendyTeamId = proto.String(trendy_team_id)
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800159 } else {
160 // Clients rely on the TrendyTeamId optional field not being set.
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800161 }
162 teamsProto[i] = teamData
Ronald Braunstein73b08ff2023-12-19 10:24:47 -0800163 }
164 return &team_proto.AllTeams{Teams: teamsProto}
165}