Minimal license feature. am: 58d85b87bc

Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/13929165

Change-Id: I49453a723ea46a2bda5d21655e569c212564c076
This commit is contained in:
Bob Badour 2021-03-19 19:35:42 +00:00 committed by Automerger Merge Worker
commit 6b4ddeb66c
7 changed files with 430 additions and 0 deletions

View File

@ -50,6 +50,7 @@ bootstrap_go_package {
"android/expand.go", "android/expand.go",
"android/filegroup.go", "android/filegroup.go",
"android/hooks.go", "android/hooks.go",
"android/license.go",
"android/makevars.go", "android/makevars.go",
"android/module.go", "android/module.go",
"android/mutator.go", "android/mutator.go",
@ -58,6 +59,7 @@ bootstrap_go_package {
"android/notices.go", "android/notices.go",
"android/onceper.go", "android/onceper.go",
"android/override_module.go", "android/override_module.go",
"android/package.go",
"android/package_ctx.go", "android/package_ctx.go",
"android/path_properties.go", "android/path_properties.go",
"android/paths.go", "android/paths.go",
@ -81,10 +83,12 @@ bootstrap_go_package {
"android/arch_test.go", "android/arch_test.go",
"android/config_test.go", "android/config_test.go",
"android/expand_test.go", "android/expand_test.go",
"android/license_test.go",
"android/namespace_test.go", "android/namespace_test.go",
"android/neverallow_test.go", "android/neverallow_test.go",
"android/onceper_test.go", "android/onceper_test.go",
"android/path_properties_test.go", "android/path_properties_test.go",
"android/package_test.go",
"android/paths_test.go", "android/paths_test.go",
"android/prebuilt_test.go", "android/prebuilt_test.go",
"android/prebuilt_etc_test.go", "android/prebuilt_etc_test.go",

69
android/license.go Normal file
View File

@ -0,0 +1,69 @@
// 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 (
"github.com/google/blueprint"
)
func init() {
RegisterModuleType("license", LicenseFactory)
}
type licenseProperties struct {
// Specifies the kinds of license that apply.
License_kinds []string
// Specifies a short copyright notice to use for the license.
Copyright_notice *string
// Specifies the path or label for the text of the license.
License_text []string `android:"path"`
// Specifies the package name to which the license applies.
Package_name *string
// Specifies where this license can be used
Visibility []string
}
type licenseModule struct {
ModuleBase
DefaultableModuleBase
properties licenseProperties
}
func (m *licenseModule) DepsMutator(ctx BottomUpMutatorContext) {
// Do nothing.
}
func (m *licenseModule) GenerateAndroidBuildActions(ctx ModuleContext) {
// Nothing to do.
}
func (m *licenseModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
// Nothing to do.
}
func LicenseFactory() Module {
module := &licenseModule{}
base := module.base()
module.AddProperties(
&base.nameProperties,
&module.properties)
base.generalProperties = module.GetProperties()
base.customizableProperties = module.GetProperties()
return module
}

150
android/license_test.go Normal file
View File

@ -0,0 +1,150 @@
package android
import (
"io/ioutil"
"os"
"testing"
)
var licenseTests = []struct {
name string
fs map[string][]byte
expectedErrors []string
}{
{
name: "license must not accept licenses property",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license {
name: "top_license",
visibility: ["//visibility:private"],
licenses: ["other_license"],
}`),
},
expectedErrors: []string{
`top/Blueprints:5:14: unrecognized property "licenses"`,
},
},
{
name: "public license",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license {
name: "top_proprietary",
license_kinds: ["top_by_exception_only"],
visibility: ["//visibility:public"],
}`),
"other/Blueprints": []byte(`
rule {
name: "arule",
licenses: ["top_proprietary"],
}`),
"yetmore/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_proprietary"],
}`),
},
},
{
name: "multiple licenses",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_proprietary"],
}
license {
name: "top_allowed_as_notice",
license_kinds: ["top_notice"],
}
license {
name: "top_proprietary",
license_kinds: ["top_by_exception_only"],
visibility: ["//visibility:public"],
}
rule {
name: "myrule",
licenses: ["top_allowed_as_notice", "top_proprietary"]
}`),
"other/Blueprints": []byte(`
rule {
name: "arule",
licenses: ["top_proprietary"],
}`),
"yetmore/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_proprietary"],
}`),
},
},
}
func TestLicense(t *testing.T) {
for _, test := range licenseTests {
t.Run(test.name, func(t *testing.T) {
_, errs := testLicense(test.fs)
expectedErrors := test.expectedErrors
if expectedErrors == nil {
FailIfErrored(t, errs)
} else {
for _, expectedError := range expectedErrors {
FailIfNoMatchingErrors(t, expectedError, errs)
}
if len(errs) > len(expectedErrors) {
t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
for i, expectedError := range expectedErrors {
t.Errorf("expectedErrors[%d] = %s", i, expectedError)
}
for i, err := range errs {
t.Errorf("errs[%d] = %s", i, err)
}
}
}
})
}
}
func testLicense(fs map[string][]byte) (*TestContext, []error) {
buildDir, err := ioutil.TempDir("", "license_test")
if err != nil {
return nil, []error{err}
}
defer os.RemoveAll(buildDir)
// Create a new config per test as visibility information is stored in the config.
env := make(map[string]string)
env["ANDROID_REQUIRE_LICENSES"] = "1"
config := TestArchConfig(buildDir, env)
ctx := NewTestArchContext()
ctx.MockFileSystem(fs)
ctx.RegisterModuleType("package", ModuleFactoryAdaptor(PackageFactory))
ctx.RegisterModuleType("license", ModuleFactoryAdaptor(LicenseFactory))
ctx.RegisterModuleType("rule", ModuleFactoryAdaptor(newMockRuleModule))
ctx.PreArchMutators(registerPackageRenamer)
ctx.Register()
_, errs := ctx.ParseBlueprintsFiles(".")
if len(errs) > 0 {
return ctx, errs
}
_, errs = ctx.PrepareBuildActions(config)
return ctx, errs
}
type mockRuleModule struct {
ModuleBase
DefaultableModuleBase
}
func newMockRuleModule() Module {
m := &mockRuleModule{}
InitAndroidModule(m)
InitDefaultableModule(m)
return m
}
func (p *mockRuleModule) GenerateAndroidBuildActions(ModuleContext) {
}
func (p *mockRuleModule) DepsMutator(BottomUpMutatorContext) {
}

View File

@ -208,6 +208,9 @@ type commonProperties struct {
// emit build rules for this module // emit build rules for this module
Enabled *bool `android:"arch_variant"` Enabled *bool `android:"arch_variant"`
// Names of the licenses that apply to this module.
Licenses []string
// control whether this module compiles for 32-bit, 64-bit, or both. Possible values // control whether this module compiles for 32-bit, 64-bit, or both. Possible values
// are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both // are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
// architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit // architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit

View File

@ -77,6 +77,7 @@ var preArch = []RegisterMutatorFunc{
ctx.TopDown("load_hooks", LoadHookMutator).Parallel() ctx.TopDown("load_hooks", LoadHookMutator).Parallel()
}, },
RegisterNamespaceMutator, RegisterNamespaceMutator,
registerPackageRenamer,
RegisterPrebuiltsPreArchMutators, RegisterPrebuiltsPreArchMutators,
RegisterDefaultsPreArchMutators, RegisterDefaultsPreArchMutators,
RegisterOverridePreArchMutators, RegisterOverridePreArchMutators,

93
android/package.go Normal file
View File

@ -0,0 +1,93 @@
// 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)
}
type packageProperties struct {
// Specifies the default visibility for all modules defined in this package.
Default_visibility []string
// Specifies the names of the default licenses for all modules defined in this package.
Default_applicable_licenses []string
}
type packageModule struct {
ModuleBase
properties packageProperties
// The module dir
name string `blueprint:"mutated"`
}
func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) {
// Nothing to do.
}
func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
// Nothing to do.
}
func (p *packageModule) DepsMutator(ctx BottomUpMutatorContext) {
// Nothing to do.
}
func (p *packageModule) Name() string {
return p.name
}
func registerPackageRenamer(ctx RegisterMutatorsContext) {
ctx.BottomUp("packages", packageRenamer).Parallel()
}
// packageRenamer ensures that every package gets named
func packageRenamer(ctx BottomUpMutatorContext) {
if p, ok := ctx.Module().(*packageModule); ok {
p.name = "//" + ctx.ModuleDir()
ctx.Rename("//" + ctx.ModuleDir())
}
}
// 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)
module.name = fmt.Sprintf("soong_package_%d", id)
module.AddProperties(&module.properties)
// The name is the relative path from build root to the directory containing this
// module. Set that name at the earliest possible moment that information is available
// which is in a LoadHook.
AddLoadHook(module, func(ctx LoadHookContext) {
module.name = "//" + ctx.ModuleDir()
})
return module
}

110
android/package_test.go Normal file
View File

@ -0,0 +1,110 @@
package android
import (
"io/ioutil"
"os"
"testing"
)
var packageTests = []struct {
name string
fs map[string][]byte
expectedErrors []string
}{
// Package default_visibility handling is tested in visibility_test.go
{
name: "package must not accept visibility and name properties",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
name: "package",
visibility: ["//visibility:private"],
}`),
},
expectedErrors: []string{
`top/Blueprints:3:10: unrecognized property "name"`,
`top/Blueprints:4:16: unrecognized property "visibility"`,
},
},
{
name: "multiple packages in separate directories",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
}`),
"other/Blueprints": []byte(`
package {
}`),
"other/nested/Blueprints": []byte(`
package {
}`),
},
},
{
name: "package must not be specified more than once per package",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
default_visibility: ["//visibility:private"],
default_applicable_licenses: ["license"],
}
package {
}`),
},
expectedErrors: []string{
`"//top" conflicts with existing module`,
},
},
}
func TestPackage(t *testing.T) {
for _, test := range packageTests {
t.Run(test.name, func(t *testing.T) {
_, errs := testPackage(test.fs)
expectedErrors := test.expectedErrors
if expectedErrors == nil {
FailIfErrored(t, errs)
} else {
for _, expectedError := range expectedErrors {
FailIfNoMatchingErrors(t, expectedError, errs)
}
if len(errs) > len(expectedErrors) {
t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
for i, expectedError := range expectedErrors {
t.Errorf("expectedErrors[%d] = %s", i, expectedError)
}
for i, err := range errs {
t.Errorf("errs[%d] = %s", i, err)
}
}
}
})
}
}
func testPackage(fs map[string][]byte) (*TestContext, []error) {
buildDir, err := ioutil.TempDir("", "package_test")
if err != nil {
return nil, []error{err}
}
defer os.RemoveAll(buildDir)
// Create a new config per test as visibility information is stored in the config.
config := TestArchConfig(buildDir, nil)
ctx := NewTestArchContext()
ctx.MockFileSystem(fs)
ctx.RegisterModuleType("package", ModuleFactoryAdaptor(PackageFactory))
ctx.PreArchMutators(registerPackageRenamer)
ctx.Register()
_, errs := ctx.ParseBlueprintsFiles(".")
if len(errs) > 0 {
return ctx, errs
}
_, errs = ctx.PrepareBuildActions(config)
return ctx, errs
}