Add team property to all modules.
This allows vendors (like google) to specify which team owns the test
module and code.
Team is a commonProperty on modules and points to the designate "team"
module. The DepsMutator adds the dependency on the "team" module and
"GenerateBuildActions" write the team data to intermediate files.
A new singleton rule, all_teams visits all modules and writes out
the proto containing the team for each module.
If a module doesn't have a team, then it finds the package in the
blueprint file and parent directory blueprint files that have a
default_team and uses that team.
*** BRANCH DIFF ***
*** BRANCH DIFF ***
Some small diffs in writing proto file on udc-branch.
i.e. write as textproto instead of binary and only write modules
with teams or default teams from package, not all modules.
This is because udc doesn't have the newer WriteFile rule from
raw_files: https://source.corp.google.com/h/android/platform/build/soong/+/31a674571e53f12dffb97698e65b9eee6ae0ebbc
*** BRANCH DIFF ***
*** BRANCH DIFF ***
Test: m all_teams
Test: go test ./python ./java ./cc ./rust ./android
Test: added team to HelloWorldHostTest and built the new asciiproto target
Test: added package default_team and checkout output proto.
Change-Id: I5c07bf489de460a04fc540f5fff0394f39f574a7
Merged-In: I5c07bf489de460a04fc540f5fff0394f39f574a7
diff --git a/android/all_teams.go b/android/all_teams.go
new file mode 100644
index 0000000..d061649
--- /dev/null
+++ b/android/all_teams.go
@@ -0,0 +1,151 @@
+package android
+
+import (
+ "android/soong/android/team_proto"
+ "path/filepath"
+
+ "github.com/google/blueprint/proptools"
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/proto"
+)
+
+const ownershipDirectory = "ownership"
+const allTeamsFile = "all_teams.pb"
+
+func AllTeamsFactory() Singleton {
+ return &allTeamsSingleton{}
+}
+
+func init() {
+ registerAllTeamBuildComponents(InitRegistrationContext)
+}
+
+func registerAllTeamBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("all_teams", AllTeamsFactory)
+}
+
+// For each module, list the team or the bpFile the module is defined in.
+type moduleTeamInfo struct {
+ teamName string
+ bpFile string
+}
+
+type allTeamsSingleton struct {
+ // Path where the collected metadata is stored after successful validation.
+ outputPath OutputPath
+
+ // Map of all package modules we visit during GenerateBuildActions
+ packages map[string]packageProperties
+ // Map of all team modules we visit during GenerateBuildActions
+ teams map[string]teamProperties
+ // Keeps track of team information or bp file for each module we visit.
+ teams_for_mods map[string]moduleTeamInfo
+}
+
+// See if there is a package module for the given bpFilePath with a team defined, if so return the team.
+// If not ascend up to the parent directory and do the same.
+func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
+ // return the Default_team listed in the package if is there.
+ if p, ok := this.packages[bpFilePath]; ok {
+ if t := p.Default_team; t != nil {
+ return this.teams[*p.Default_team], true
+ }
+ }
+ // Strip a directory and go up.
+ // Does android/paths.go basePath,SourcePath help?
+ current, base := filepath.Split(bpFilePath)
+ current = filepath.Clean(current) // removes trailing slash, convert "" -> "."
+ parent, _ := filepath.Split(current)
+ if current == "." {
+ return teamProperties{}, false
+ }
+ return this.lookupDefaultTeam(filepath.Join(parent, base))
+}
+
+// Create a rule to run a tool to collect all the intermediate files
+// which list the team per module into one proto file.
+func (this *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
+ this.packages = make(map[string]packageProperties)
+ this.teams = make(map[string]teamProperties)
+ this.teams_for_mods = make(map[string]moduleTeamInfo)
+
+ ctx.VisitAllModules(func(module Module) {
+ if !module.Enabled() {
+ return
+ }
+
+ bpFile := ctx.BlueprintFile(module)
+
+ // Package Modules and Team Modules are stored in a map so we can look them up by name for
+ // modules without a team.
+ if pack, ok := module.(*packageModule); ok {
+ // Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in this context.
+ pkgKey := bpFile
+ this.packages[pkgKey] = pack.properties
+ return
+ }
+ if team, ok := module.(*teamModule); ok {
+ this.teams[team.Name()] = team.properties
+ return
+ }
+
+ // If a team name is given for a module, store it.
+ // Otherwise store the bpFile so we can do a package walk later.
+ if module.base().Team() != "" {
+ this.teams_for_mods[module.Name()] = moduleTeamInfo{teamName: module.base().Team(), bpFile: bpFile}
+ } else {
+ this.teams_for_mods[module.Name()] = moduleTeamInfo{bpFile: bpFile}
+ }
+ })
+
+ // Visit all modules again and lookup the team name in the package or parent package if the team
+ // isn't assignged at the module level.
+ allTeams := this.lookupTeamForAllModules()
+
+ this.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
+ // udc branch diff, use textproto and encode it.
+ data, err := prototext.Marshal(allTeams)
+ if err != nil {
+ ctx.Errorf("Unable to marshal team data. %s", err)
+ }
+
+ WriteFileRuleVerbatim(ctx, this.outputPath, proptools.NinjaEscape(string(data)))
+ ctx.Phony("all_teams", this.outputPath)
+}
+
+func (this *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
+ ctx.DistForGoal("all_teams", this.outputPath)
+}
+
+// Visit every (non-package, non-team) module and write out a proto containing
+// either the declared team data for that module or the package default team data for that module.
+func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
+ teamsProto := make([]*team_proto.Team, len(this.teams_for_mods))
+ i := 0
+ for moduleName, m := range this.teams_for_mods {
+ teamName := m.teamName
+ var teamProperties teamProperties
+ found := false
+ if teamName != "" {
+ teamProperties, found = this.teams[teamName]
+ } else {
+ teamProperties, found = this.lookupDefaultTeam(m.bpFile)
+ }
+
+ // udc branch diff, only write modules with teams to keep ninja file smaller.
+ if found {
+ trendy_team_id := *teamProperties.Trendy_team_id
+ var files []string
+ teamData := new(team_proto.Team)
+ *teamData = team_proto.Team{
+ TrendyTeamId: proto.String(trendy_team_id),
+ TargetName: proto.String(moduleName),
+ Path: proto.String(m.bpFile),
+ File: files,
+ }
+ teamsProto[i] = teamData
+ i++
+ }
+ }
+ return &team_proto.AllTeams{Teams: teamsProto[:i]}
+}