blob: d061649da663914387f3ac61590613fac5cee321 [file] [log] [blame]
Ronald Braunstein57f23492023-12-19 10:24:47 -08001package android
2
3import (
4 "android/soong/android/team_proto"
5 "path/filepath"
6
7 "github.com/google/blueprint/proptools"
8 "google.golang.org/protobuf/encoding/prototext"
9 "google.golang.org/protobuf/proto"
10)
11
12const ownershipDirectory = "ownership"
13const allTeamsFile = "all_teams.pb"
14
15func AllTeamsFactory() Singleton {
16 return &allTeamsSingleton{}
17}
18
19func init() {
20 registerAllTeamBuildComponents(InitRegistrationContext)
21}
22
23func registerAllTeamBuildComponents(ctx RegistrationContext) {
24 ctx.RegisterSingletonType("all_teams", AllTeamsFactory)
25}
26
27// For each module, list the team or the bpFile the module is defined in.
28type moduleTeamInfo struct {
29 teamName string
30 bpFile string
31}
32
33type allTeamsSingleton struct {
34 // Path where the collected metadata is stored after successful validation.
35 outputPath OutputPath
36
37 // Map of all package modules we visit during GenerateBuildActions
38 packages map[string]packageProperties
39 // Map of all team modules we visit during GenerateBuildActions
40 teams map[string]teamProperties
41 // Keeps track of team information or bp file for each module we visit.
42 teams_for_mods map[string]moduleTeamInfo
43}
44
45// See if there is a package module for the given bpFilePath with a team defined, if so return the team.
46// If not ascend up to the parent directory and do the same.
47func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
48 // return the Default_team listed in the package if is there.
49 if p, ok := this.packages[bpFilePath]; ok {
50 if t := p.Default_team; t != nil {
51 return this.teams[*p.Default_team], true
52 }
53 }
54 // Strip a directory and go up.
55 // Does android/paths.go basePath,SourcePath help?
56 current, base := filepath.Split(bpFilePath)
57 current = filepath.Clean(current) // removes trailing slash, convert "" -> "."
58 parent, _ := filepath.Split(current)
59 if current == "." {
60 return teamProperties{}, false
61 }
62 return this.lookupDefaultTeam(filepath.Join(parent, base))
63}
64
65// Create a rule to run a tool to collect all the intermediate files
66// which list the team per module into one proto file.
67func (this *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
68 this.packages = make(map[string]packageProperties)
69 this.teams = make(map[string]teamProperties)
70 this.teams_for_mods = make(map[string]moduleTeamInfo)
71
72 ctx.VisitAllModules(func(module Module) {
73 if !module.Enabled() {
74 return
75 }
76
77 bpFile := ctx.BlueprintFile(module)
78
79 // Package Modules and Team Modules are stored in a map so we can look them up by name for
80 // modules without a team.
81 if pack, ok := module.(*packageModule); ok {
82 // Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in this context.
83 pkgKey := bpFile
84 this.packages[pkgKey] = pack.properties
85 return
86 }
87 if team, ok := module.(*teamModule); ok {
88 this.teams[team.Name()] = team.properties
89 return
90 }
91
92 // If a team name is given for a module, store it.
93 // Otherwise store the bpFile so we can do a package walk later.
94 if module.base().Team() != "" {
95 this.teams_for_mods[module.Name()] = moduleTeamInfo{teamName: module.base().Team(), bpFile: bpFile}
96 } else {
97 this.teams_for_mods[module.Name()] = moduleTeamInfo{bpFile: bpFile}
98 }
99 })
100
101 // Visit all modules again and lookup the team name in the package or parent package if the team
102 // isn't assignged at the module level.
103 allTeams := this.lookupTeamForAllModules()
104
105 this.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
106 // udc branch diff, use textproto and encode it.
107 data, err := prototext.Marshal(allTeams)
108 if err != nil {
109 ctx.Errorf("Unable to marshal team data. %s", err)
110 }
111
112 WriteFileRuleVerbatim(ctx, this.outputPath, proptools.NinjaEscape(string(data)))
113 ctx.Phony("all_teams", this.outputPath)
114}
115
116func (this *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
117 ctx.DistForGoal("all_teams", this.outputPath)
118}
119
120// Visit every (non-package, non-team) module and write out a proto containing
121// either the declared team data for that module or the package default team data for that module.
122func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
123 teamsProto := make([]*team_proto.Team, len(this.teams_for_mods))
124 i := 0
125 for moduleName, m := range this.teams_for_mods {
126 teamName := m.teamName
127 var teamProperties teamProperties
128 found := false
129 if teamName != "" {
130 teamProperties, found = this.teams[teamName]
131 } else {
132 teamProperties, found = this.lookupDefaultTeam(m.bpFile)
133 }
134
135 // udc branch diff, only write modules with teams to keep ninja file smaller.
136 if found {
137 trendy_team_id := *teamProperties.Trendy_team_id
138 var files []string
139 teamData := new(team_proto.Team)
140 *teamData = team_proto.Team{
141 TrendyTeamId: proto.String(trendy_team_id),
142 TargetName: proto.String(moduleName),
143 Path: proto.String(m.bpFile),
144 File: files,
145 }
146 teamsProto[i] = teamData
147 i++
148 }
149 }
150 return &team_proto.AllTeams{Teams: teamsProto[:i]}
151}