aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.bp18
-rw-r--r--android/prebuilt_etc.go62
-rw-r--r--java/java_test.go2
-rw-r--r--java/sdk_library.go4
-rw-r--r--xml/xml.go136
-rw-r--r--xml/xml_test.go86
6 files changed, 280 insertions, 28 deletions
diff --git a/Android.bp b/Android.bp
index aa652096..4a06a113 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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
//
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index fee2c494..55a72a6a 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -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) SourceFilePath(ctx ModuleContext) Path {
+ return ctx.ExpandSource(String(p.properties.Src), "src")
}
-func (p *prebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
- p.sourceFilePath = ctx.ExpandSource(p.properties.Srcs[0], "srcs")
+// 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
}
diff --git a/java/java_test.go b/java/java_test.go
index de514e04..ea524962 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -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
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 13a9275c..2396467f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -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)
diff --git a/xml/xml.go b/xml/xml.go
new file mode 100644
index 00000000..218d73ce
--- /dev/null
+++ b/xml/xml.go
@@ -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
+}
diff --git a/xml/xml_test.go b/xml/xml_test.go
new file mode 100644
index 00000000..e8fa49c2
--- /dev/null
+++ b/xml/xml_test.go
@@ -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)
+ }
+}