Add prebuilt_etc_xml

am: 5a8d1bee89

Change-Id: I8b54e220fc8c926ff809fae180249dbffd8969b5
This commit is contained in:
Jiyong Park
2018-04-27 10:25:18 -07:00
committed by android-build-merger
6 changed files with 280 additions and 28 deletions

View File

@@ -291,6 +291,24 @@ bootstrap_go_package {
],
}
bootstrap_go_package {
name: "soong-xml",
pkgPath: "android/soong/xml",
deps: [
"blueprint",
"blueprint-pathtools",
"soong",
"soong-android",
],
srcs: [
"xml/xml.go",
],
testSrcs: [
"xml/xml_test.go",
],
pluginFor: ["soong_build"],
}
//
// Defaults to enable various configurations of host bionic
//

View File

@@ -28,45 +28,47 @@ func init() {
type prebuiltEtcProperties struct {
// Source file of this prebuilt.
Srcs []string `android:"arch_variant"`
Src *string `android:"arch_variant"`
// optional subdirectory under which this file is installed into
Sub_dir *string `android:"arch_variant"`
}
type prebuiltEtc struct {
type PrebuiltEtc struct {
ModuleBase
prebuilt Prebuilt
properties prebuiltEtcProperties
sourceFilePath Path
installDirPath OutputPath
sourceFilePath Path
installDirPath OutputPath
additionalDependencies *Paths
}
func (p *prebuiltEtc) Prebuilt() *Prebuilt {
return &p.prebuilt
}
func (p *prebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
if len(p.properties.Srcs) == 0 {
ctx.PropertyErrorf("srcs", "missing prebuilt source file")
}
if len(p.properties.Srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
func (p *PrebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
if p.properties.Src == nil {
ctx.PropertyErrorf("src", "missing prebuilt source file")
}
// To support ":modulename" in src
ExtractSourceDeps(ctx, &(p.properties.Srcs)[0])
ExtractSourceDeps(ctx, p.properties.Src)
}
func (p *prebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
p.sourceFilePath = ctx.ExpandSource(p.properties.Srcs[0], "srcs")
func (p *PrebuiltEtc) SourceFilePath(ctx ModuleContext) Path {
return ctx.ExpandSource(String(p.properties.Src), "src")
}
// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
// additional steps (like validating the src) before the file is installed.
func (p *PrebuiltEtc) SetAdditionalDependencies(paths Paths) {
p.additionalDependencies = &paths
}
func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
p.sourceFilePath = ctx.ExpandSource(String(p.properties.Src), "src")
p.installDirPath = PathForModuleInstall(ctx, "etc", String(p.properties.Sub_dir))
}
func (p *prebuiltEtc) AndroidMk() AndroidMkData {
func (p *PrebuiltEtc) AndroidMk() AndroidMkData {
return AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
@@ -76,16 +78,26 @@ func (p *prebuiltEtc) AndroidMk() AndroidMkData {
fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.sourceFilePath.String())
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
if p.additionalDependencies != nil {
fmt.Fprint(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=")
for _, path := range *p.additionalDependencies {
fmt.Fprint(w, " "+path.String())
}
fmt.Fprintln(w, "")
}
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
},
}
}
func PrebuiltEtcFactory() Module {
module := &prebuiltEtc{}
module.AddProperties(&module.properties)
func InitPrebuiltEtcModule(p *PrebuiltEtc) {
p.AddProperties(&p.properties)
}
InitPrebuiltModule(module, &(module.properties.Srcs))
InitAndroidModule(module)
func PrebuiltEtcFactory() Module {
module := &PrebuiltEtc{}
InitPrebuiltEtcModule(module)
// This module is device-only
InitAndroidArchModule(module, DeviceSupported, MultilibCommon)
return module
}

View File

@@ -1040,7 +1040,7 @@ func TestJavaSdkLibrary(t *testing.T) {
ctx.ModuleForTests("foo"+sdkDocsSuffix, "android_common")
ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkSystemApiSuffix, "android_common")
ctx.ModuleForTests("foo"+sdkImplLibrarySuffix, "android_common")
ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "")
ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
bazJavac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
// tests if baz is actually linked to the stubs lib

View File

@@ -407,14 +407,14 @@ func (module *sdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
// <partition>/etc/permissions
etcProps := struct {
Name *string
Srcs []string
Src *string
Sub_dir *string
Soc_specific *bool
Device_specific *bool
Product_specific *bool
}{}
etcProps.Name = proptools.StringPtr(module.xmlFileName())
etcProps.Srcs = []string{":" + module.xmlFileName() + "-gen"}
etcProps.Src = proptools.StringPtr(":" + module.xmlFileName() + "-gen")
etcProps.Sub_dir = proptools.StringPtr("permissions")
if module.SocSpecific() {
etcProps.Soc_specific = proptools.BoolPtr(true)

136
xml/xml.go Normal file
View File

@@ -0,0 +1,136 @@
// Copyright 2018 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 xml
import (
"android/soong/android"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
// prebuilt_etc_xml installs an xml file under <partition>/etc/<subdir>.
// It also optionally validates the xml file against the schema.
var (
pctx = android.NewPackageContext("android/soong/xml")
xmllintDtd = pctx.AndroidStaticRule("xmllint-dtd",
blueprint.RuleParams{
Command: `$XmlLintCmd --dtdvalid $dtd $in > /dev/null && touch -a $out`,
CommandDeps: []string{"$XmlLintCmd"},
Restat: true,
},
"dtd")
xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd",
blueprint.RuleParams{
Command: `$XmlLintCmd --schema $xsd $in > /dev/null && touch -a $out`,
CommandDeps: []string{"$XmlLintCmd"},
Restat: true,
},
"xsd")
xmllintMinimal = pctx.AndroidStaticRule("xmllint-minimal",
blueprint.RuleParams{
Command: `$XmlLintCmd $in > /dev/null && touch -a $out`,
CommandDeps: []string{"$XmlLintCmd"},
Restat: true,
})
)
func init() {
android.RegisterModuleType("prebuilt_etc_xml", PrebuiltEtcXmlFactory)
pctx.HostBinToolVariable("XmlLintCmd", "xmllint")
}
type prebuiltEtcXmlProperties struct {
// Optional DTD that will be used to validate the xml file.
Schema *string
}
type prebuiltEtcXml struct {
android.PrebuiltEtc
properties prebuiltEtcXmlProperties
}
func (p *prebuiltEtcXml) timestampFilePath(ctx android.ModuleContext) android.WritablePath {
return android.PathForModuleOut(ctx, p.PrebuiltEtc.SourceFilePath(ctx).Base()+"-timestamp")
}
func (p *prebuiltEtcXml) DepsMutator(ctx android.BottomUpMutatorContext) {
p.PrebuiltEtc.DepsMutator(ctx)
// To support ":modulename" in schema
android.ExtractSourceDeps(ctx, p.properties.Schema)
}
func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
p.PrebuiltEtc.GenerateAndroidBuildActions(ctx)
if p.properties.Schema != nil {
schema := ctx.ExpandSource(proptools.String(p.properties.Schema), "schema")
switch schema.Ext() {
case ".dtd":
ctx.Build(pctx, android.BuildParams{
Rule: xmllintDtd,
Description: "xmllint-dtd",
Input: p.PrebuiltEtc.SourceFilePath(ctx),
Output: p.timestampFilePath(ctx),
Implicit: schema,
Args: map[string]string{
"dtd": schema.String(),
},
})
break
case ".xsd":
ctx.Build(pctx, android.BuildParams{
Rule: xmllintXsd,
Description: "xmllint-xsd",
Input: p.PrebuiltEtc.SourceFilePath(ctx),
Output: p.timestampFilePath(ctx),
Implicit: schema,
Args: map[string]string{
"xsd": schema.String(),
},
})
break
default:
ctx.PropertyErrorf("schema", "not supported extension: %q", schema.Ext())
}
} else {
// when schema is not specified, just check if the xml is well-formed
ctx.Build(pctx, android.BuildParams{
Rule: xmllintMinimal,
Description: "xmllint-minimal",
Input: p.PrebuiltEtc.SourceFilePath(ctx),
Output: p.timestampFilePath(ctx),
})
}
p.SetAdditionalDependencies([]android.Path{p.timestampFilePath(ctx)})
}
func PrebuiltEtcXmlFactory() android.Module {
module := &prebuiltEtcXml{}
module.AddProperties(&module.properties)
android.InitPrebuiltEtcModule(&module.PrebuiltEtc)
// This module is device-only
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}

86
xml/xml_test.go Normal file
View File

@@ -0,0 +1,86 @@
// Copyright 2018 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 xml
import (
"android/soong/android"
"io/ioutil"
"os"
"testing"
)
func testXml(t *testing.T, bp string) *android.TestContext {
config, buildDir := setup(t)
defer teardown(buildDir)
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
ctx.RegisterModuleType("prebuilt_etc_xml", android.ModuleFactoryAdaptor(PrebuiltEtcXmlFactory))
ctx.Register()
mockFiles := map[string][]byte{
"Android.bp": []byte(bp),
"foo.xml": nil,
"foo.dtd": nil,
"bar.xml": nil,
"bar.xsd": nil,
}
ctx.MockFileSystem(mockFiles)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
return ctx
}
func setup(t *testing.T) (config android.Config, buildDir string) {
buildDir, err := ioutil.TempDir("", "soong_xml_test")
if err != nil {
t.Fatal(err)
}
config = android.TestArchConfig(buildDir, nil)
return
}
func teardown(buildDir string) {
os.RemoveAll(buildDir)
}
// Minimal test
func TestPrebuiltEtcXml(t *testing.T) {
ctx := testXml(t, `
prebuilt_etc_xml {
name: "foo.xml",
src: "foo.xml",
schema: "foo.dtd",
}
prebuilt_etc_xml {
name: "bar.xml",
src: "bar.xml",
schema: "bar.xsd",
}
`)
xmllint := ctx.ModuleForTests("foo.xml", "android_common").Rule("xmllint")
input := xmllint.Input.String()
if input != "foo.xml" {
t.Errorf("input expected %q != got %q", "foo.xml", input)
}
schema := xmllint.Args["dtd"]
if schema != "foo.dtd" {
t.Errorf("dtd expected %q != got %q", "foo.dtdl", schema)
}
}