|  | // Copyright 2019 Google Inc. All rights reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package android | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "sync/atomic" | 
|  |  | 
|  | "github.com/google/blueprint" | 
|  | ) | 
|  |  | 
|  | func init() { | 
|  | RegisterModuleType("package", PackageFactory) | 
|  | } | 
|  |  | 
|  | // The information maintained about each package. | 
|  | type packageInfo struct { | 
|  | // The module from which this information was populated. If `duplicated` = true then this is the | 
|  | // module that has been renamed and must be used to report errors. | 
|  | module *packageModule | 
|  |  | 
|  | // If true this indicates that there are two package statements in the same package which is not | 
|  | // allowed and will cause the build to fail. This flag is set by packageRenamer and checked in | 
|  | // packageErrorReporter | 
|  | duplicated bool | 
|  | } | 
|  |  | 
|  | type packageProperties struct { | 
|  | Name string `blueprint:"mutated"` | 
|  |  | 
|  | // Specifies the default visibility for all modules defined in this package. | 
|  | Default_visibility []string | 
|  | } | 
|  |  | 
|  | type packageModule struct { | 
|  | ModuleBase | 
|  |  | 
|  | properties  packageProperties | 
|  | packageInfo *packageInfo | 
|  | } | 
|  |  | 
|  | func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) { | 
|  | // Nothing to do. | 
|  | } | 
|  |  | 
|  | func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) { | 
|  | // Nothing to do. | 
|  | } | 
|  |  | 
|  | func (p *packageModule) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName { | 
|  | // Override to create a package id. | 
|  | return newPackageId(ctx.ModuleDir()) | 
|  | } | 
|  |  | 
|  | func (p *packageModule) Name() string { | 
|  | return p.properties.Name | 
|  | } | 
|  |  | 
|  | func (p *packageModule) setName(name string) { | 
|  | p.properties.Name = name | 
|  | } | 
|  |  | 
|  | // Counter to ensure package modules are created with a unique name within whatever namespace they | 
|  | // belong. | 
|  | var packageCount uint32 = 0 | 
|  |  | 
|  | func PackageFactory() Module { | 
|  | module := &packageModule{} | 
|  |  | 
|  | // Get a unique if for the package. Has to be done atomically as the creation of the modules are | 
|  | // done in parallel. | 
|  | id := atomic.AddUint32(&packageCount, 1) | 
|  | name := fmt.Sprintf("soong_package_%d", id) | 
|  |  | 
|  | module.properties.Name = name | 
|  |  | 
|  | module.AddProperties(&module.properties) | 
|  |  | 
|  | // The default_visibility property needs to be checked and parsed by the visibility module during | 
|  | // its checking and parsing phases. | 
|  | module.primaryVisibilityProperty = | 
|  | newVisibilityProperty("default_visibility", &module.properties.Default_visibility) | 
|  | module.visibilityPropertyInfo = []visibilityProperty{module.primaryVisibilityProperty} | 
|  |  | 
|  | return module | 
|  | } | 
|  |  | 
|  | // Registers the function that renames the packages. | 
|  | func registerPackageRenamer(ctx RegisterMutatorsContext) { | 
|  | ctx.BottomUp("packageRenamer", packageRenamer).Parallel() | 
|  | ctx.BottomUp("packageErrorReporter", packageErrorReporter).Parallel() | 
|  | } | 
|  |  | 
|  | // Renames the package to match the package directory. | 
|  | // | 
|  | // This also creates a PackageInfo object for each package and uses that to detect and remember | 
|  | // duplicates for later error reporting. | 
|  | func packageRenamer(ctx BottomUpMutatorContext) { | 
|  | m, ok := ctx.Module().(*packageModule) | 
|  | if !ok { | 
|  | return | 
|  | } | 
|  |  | 
|  | packageName := "//" + ctx.ModuleDir() | 
|  |  | 
|  | pi := newPackageInfo(ctx, packageName, m) | 
|  | if pi.module != m { | 
|  | // Remember that the package was duplicated but do not rename as that will cause an error to | 
|  | // be logged with the generated name. Similarly, reporting the error here will use the generated | 
|  | // name as renames are only processed after this phase. | 
|  | pi.duplicated = true | 
|  | } else { | 
|  | // This is the first package module in this package so rename it to match the package name. | 
|  | m.setName(packageName) | 
|  | ctx.Rename(packageName) | 
|  |  | 
|  | // Store a package info reference in the module. | 
|  | m.packageInfo = pi | 
|  | } | 
|  | } | 
|  |  | 
|  | // Logs any deferred errors. | 
|  | func packageErrorReporter(ctx BottomUpMutatorContext) { | 
|  | m, ok := ctx.Module().(*packageModule) | 
|  | if !ok { | 
|  | return | 
|  | } | 
|  |  | 
|  | packageDir := ctx.ModuleDir() | 
|  | packageName := "//" + packageDir | 
|  |  | 
|  | // Get the PackageInfo for the package. Should have been populated in the packageRenamer phase. | 
|  | pi := findPackageInfo(ctx, packageName) | 
|  | if pi == nil { | 
|  | ctx.ModuleErrorf("internal error, expected package info to be present for package '%s'", | 
|  | packageName) | 
|  | return | 
|  | } | 
|  |  | 
|  | if pi.module != m { | 
|  | // The package module has been duplicated but this is not the module that has been renamed so | 
|  | // ignore it. An error will be logged for the renamed module which will ensure that the error | 
|  | // message uses the correct name. | 
|  | return | 
|  | } | 
|  |  | 
|  | // Check to see whether there are duplicate package modules in the package. | 
|  | if pi.duplicated { | 
|  | ctx.ModuleErrorf("package {...} specified multiple times") | 
|  | return | 
|  | } | 
|  | } | 
|  |  | 
|  | type defaultPackageInfoKey string | 
|  |  | 
|  | func newPackageInfo( | 
|  | ctx BaseModuleContext, packageName string, module *packageModule) *packageInfo { | 
|  | key := NewCustomOnceKey(defaultPackageInfoKey(packageName)) | 
|  |  | 
|  | return ctx.Config().Once(key, func() interface{} { | 
|  | return &packageInfo{module: module} | 
|  | }).(*packageInfo) | 
|  | } | 
|  |  | 
|  | // Get the PackageInfo for the package name (starts with //, no trailing /), is nil if no package | 
|  | // module type was specified. | 
|  | func findPackageInfo(ctx BaseModuleContext, packageName string) *packageInfo { | 
|  | key := NewCustomOnceKey(defaultPackageInfoKey(packageName)) | 
|  |  | 
|  | pi := ctx.Config().Once(key, func() interface{} { | 
|  | return nil | 
|  | }) | 
|  |  | 
|  | if pi == nil { | 
|  | return nil | 
|  | } else { | 
|  | return pi.(*packageInfo) | 
|  | } | 
|  | } |