platform_build_soong/android/licenses.go
Paul Duffin 3c298a3725 Reformat license code to comply with preupload checks
Bug: 181070625
Test: m nothing
Change-Id: I0b7c8613fcb7bc4e96908e391f1e46a9168f2507
2021-03-04 22:35:29 +00:00

295 lines
10 KiB
Go

// Copyright 2020 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 (
"reflect"
"sync"
"github.com/google/blueprint"
)
// Adds cross-cutting licenses dependency to propagate license metadata through the build system.
//
// Stage 1 - bottom-up records package-level default_applicable_licenses property mapped by package name.
// Stage 2 - bottom-up converts licenses property or package default_applicable_licenses to dependencies.
// Stage 3 - bottom-up type-checks every added applicable license dependency and license_kind dependency.
// Stage 4 - GenerateBuildActions calculates properties for the union of license kinds, conditions and texts.
type licensesDependencyTag struct {
blueprint.BaseDependencyTag
}
var (
licensesTag = licensesDependencyTag{}
)
// Describes the property provided by a module to reference applicable licenses.
type applicableLicensesProperty interface {
// The name of the property. e.g. default_applicable_licenses or licenses
getName() string
// The values assigned to the property. (Must reference license modules.)
getStrings() []string
}
type applicableLicensesPropertyImpl struct {
name string
licensesProperty *[]string
}
func newApplicableLicensesProperty(name string, licensesProperty *[]string) applicableLicensesProperty {
return applicableLicensesPropertyImpl{
name: name,
licensesProperty: licensesProperty,
}
}
func (p applicableLicensesPropertyImpl) getName() string {
return p.name
}
func (p applicableLicensesPropertyImpl) getStrings() []string {
return *p.licensesProperty
}
// Set the primary applicable licenses property for a module.
func setPrimaryLicensesProperty(module Module, name string, licensesProperty *[]string) {
module.base().primaryLicensesProperty = newApplicableLicensesProperty(name, licensesProperty)
}
// Storage blob for a package's default_applicable_licenses mapped by package directory.
type licensesContainer struct {
licenses []string
}
func (r licensesContainer) getLicenses() []string {
return r.licenses
}
var packageDefaultLicensesMap = NewOnceKey("packageDefaultLicensesMap")
// The map from package dir name to default applicable licenses as a licensesContainer.
func moduleToPackageDefaultLicensesMap(config Config) *sync.Map {
return config.Once(packageDefaultLicensesMap, func() interface{} {
return &sync.Map{}
}).(*sync.Map)
}
// Registers the function that maps each package to its default_applicable_licenses.
//
// This goes before defaults expansion so the defaults can pick up the package default.
func RegisterLicensesPackageMapper(ctx RegisterMutatorsContext) {
ctx.BottomUp("licensesPackageMapper", licensesPackageMapper).Parallel()
}
// Registers the function that gathers the license dependencies for each module.
//
// This goes after defaults expansion so that it can pick up default licenses and before visibility enforcement.
func RegisterLicensesPropertyGatherer(ctx RegisterMutatorsContext) {
ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer).Parallel()
}
// Registers the function that verifies the licenses and license_kinds dependency types for each module.
func RegisterLicensesDependencyChecker(ctx RegisterMutatorsContext) {
ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker).Parallel()
}
// Maps each package to its default applicable licenses.
func licensesPackageMapper(ctx BottomUpMutatorContext) {
p, ok := ctx.Module().(*packageModule)
if !ok {
return
}
licenses := getLicenses(ctx, p)
dir := ctx.ModuleDir()
c := makeLicensesContainer(licenses)
moduleToPackageDefaultLicensesMap(ctx.Config()).Store(dir, c)
}
// Copies the default_applicable_licenses property values for mapping by package directory.
func makeLicensesContainer(propVals []string) licensesContainer {
licenses := make([]string, 0, len(propVals))
licenses = append(licenses, propVals...)
return licensesContainer{licenses}
}
// Gathers the applicable licenses into dependency references after defaults expansion.
func licensesPropertyGatherer(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
return
}
if exemptFromRequiredApplicableLicensesProperty(m) {
return
}
licenses := getLicenses(ctx, m)
ctx.AddVariationDependencies(nil, licensesTag, licenses...)
}
// Verifies the license and license_kind dependencies are each the correct kind of module.
func licensesDependencyChecker(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
return
}
// license modules have no licenses, but license_kinds must refer to license_kind modules
if _, ok := m.(*licenseModule); ok {
for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
if _, ok := module.(*licenseKindModule); !ok {
ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
}
}
return
}
if exemptFromRequiredApplicableLicensesProperty(m) {
return
}
for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
if _, ok := module.(*licenseModule); !ok {
propertyName := "licenses"
primaryProperty := m.base().primaryLicensesProperty
if primaryProperty != nil {
propertyName = primaryProperty.getName()
}
ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module))
}
}
}
// Flattens license and license_kind dependencies into calculated properties.
//
// Re-validates applicable licenses properties refer only to license modules and license_kinds properties refer
// only to license_kind modules.
func licensesPropertyFlattener(ctx ModuleContext) {
m, ok := ctx.Module().(Module)
if !ok {
return
}
// license modules have no licenses, but license_kinds must refer to license_kind modules
if l, ok := m.(*licenseModule); ok {
mergeProps(&m.base().commonProperties.Effective_licenses, ctx.ModuleName())
mergeProps(&m.base().commonProperties.Effective_license_text, PathsForModuleSrc(ctx, l.properties.License_text).Strings()...)
for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
if lk, ok := module.(*licenseKindModule); ok {
mergeProps(&m.base().commonProperties.Effective_license_conditions, lk.properties.Conditions...)
mergeProps(&m.base().commonProperties.Effective_license_kinds, ctx.OtherModuleName(module))
} else {
ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
}
}
return
}
if exemptFromRequiredApplicableLicensesProperty(m) {
return
}
for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
if l, ok := module.(*licenseModule); ok {
if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil {
m.base().commonProperties.Effective_package_name = l.properties.Package_name
}
mergeProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...)
mergeProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...)
mergeProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...)
mergeProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...)
} else {
propertyName := "licenses"
primaryProperty := m.base().primaryLicensesProperty
if primaryProperty != nil {
propertyName = primaryProperty.getName()
}
ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module))
}
}
}
// Update a property string array with a distinct union of its values and a list of new values.
func mergeProps(prop *[]string, values ...string) {
s := make(map[string]bool)
for _, v := range *prop {
s[v] = true
}
for _, v := range values {
s[v] = true
}
*prop = []string{}
*prop = append(*prop, SortedStringKeys(s)...)
}
// Get the licenses property falling back to the package default.
func getLicenses(ctx BaseModuleContext, module Module) []string {
if exemptFromRequiredApplicableLicensesProperty(module) {
return nil
}
primaryProperty := module.base().primaryLicensesProperty
if primaryProperty == nil {
if ctx.Config().IsEnvTrue("ANDROID_REQUIRE_LICENSES") {
ctx.ModuleErrorf("module type %q must have an applicable licenses property", ctx.OtherModuleType(module))
}
return nil
}
licenses := primaryProperty.getStrings()
if len(licenses) > 0 {
s := make(map[string]bool)
for _, l := range licenses {
if _, ok := s[l]; ok {
ctx.ModuleErrorf("duplicate %q %s", l, primaryProperty.getName())
}
s[l] = true
}
return licenses
}
dir := ctx.OtherModuleDir(module)
moduleToApplicableLicenses := moduleToPackageDefaultLicensesMap(ctx.Config())
value, ok := moduleToApplicableLicenses.Load(dir)
var c licensesContainer
if ok {
c = value.(licensesContainer)
} else {
c = licensesContainer{}
}
return c.getLicenses()
}
// Returns whether a module is an allowed list of modules that do not have or need applicable licenses.
func exemptFromRequiredApplicableLicensesProperty(module Module) bool {
switch reflect.TypeOf(module).String() {
case "*android.licenseModule": // is a license, doesn't need one
case "*android.licenseKindModule": // is a license, doesn't need one
case "*android.NamespaceModule": // just partitions things, doesn't add anything
case "*android.soongConfigModuleTypeModule": // creates aliases for modules with licenses
case "*android.soongConfigModuleTypeImport": // creates aliases for modules with licenses
case "*android.soongConfigStringVariableDummyModule": // used for creating aliases
case "*android.SoongConfigBoolVariableDummyModule": // used for creating aliases
default:
return false
}
return true
}