• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package xml
16
17import (
18	"android/soong/android"
19	"android/soong/bazel"
20	"android/soong/etc"
21
22	"github.com/google/blueprint"
23	"github.com/google/blueprint/proptools"
24)
25
26// prebuilt_etc_xml installs an xml file under <partition>/etc/<subdir>.
27// It also optionally validates the xml file against the schema.
28
29var (
30	pctx = android.NewPackageContext("android/soong/xml")
31
32	xmllintDtd = pctx.AndroidStaticRule("xmllint-dtd",
33		blueprint.RuleParams{
34			Command:     `$XmlLintCmd --dtdvalid $dtd $in > /dev/null && touch -a $out`,
35			CommandDeps: []string{"$XmlLintCmd"},
36			Restat:      true,
37		},
38		"dtd")
39
40	xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd",
41		blueprint.RuleParams{
42			Command:     `$XmlLintCmd --schema $xsd $in > /dev/null && touch -a $out`,
43			CommandDeps: []string{"$XmlLintCmd"},
44			Restat:      true,
45		},
46		"xsd")
47
48	xmllintMinimal = pctx.AndroidStaticRule("xmllint-minimal",
49		blueprint.RuleParams{
50			Command:     `$XmlLintCmd $in > /dev/null && touch -a $out`,
51			CommandDeps: []string{"$XmlLintCmd"},
52			Restat:      true,
53		})
54)
55
56func init() {
57	registerXmlBuildComponents(android.InitRegistrationContext)
58	pctx.HostBinToolVariable("XmlLintCmd", "xmllint")
59}
60
61func registerXmlBuildComponents(ctx android.RegistrationContext) {
62	ctx.RegisterModuleType("prebuilt_etc_xml", PrebuiltEtcXmlFactory)
63}
64
65type prebuiltEtcXmlProperties struct {
66	// Optional DTD that will be used to validate the xml file.
67	Schema *string `android:"path"`
68}
69
70type prebuiltEtcXml struct {
71	android.BazelModuleBase
72
73	etc.PrebuiltEtc
74
75	properties prebuiltEtcXmlProperties
76}
77
78func (p *prebuiltEtcXml) timestampFilePath(ctx android.ModuleContext) android.WritablePath {
79	return android.PathForModuleOut(ctx, p.PrebuiltEtc.SourceFilePath(ctx).Base()+"-timestamp")
80}
81
82func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
83	p.PrebuiltEtc.GenerateAndroidBuildActions(ctx)
84
85	if p.properties.Schema != nil {
86		schema := android.PathForModuleSrc(ctx, proptools.String(p.properties.Schema))
87
88		switch schema.Ext() {
89		case ".dtd":
90			ctx.Build(pctx, android.BuildParams{
91				Rule:        xmllintDtd,
92				Description: "xmllint-dtd",
93				Input:       p.PrebuiltEtc.SourceFilePath(ctx),
94				Output:      p.timestampFilePath(ctx),
95				Implicit:    schema,
96				Args: map[string]string{
97					"dtd": schema.String(),
98				},
99			})
100			break
101		case ".xsd":
102			ctx.Build(pctx, android.BuildParams{
103				Rule:        xmllintXsd,
104				Description: "xmllint-xsd",
105				Input:       p.PrebuiltEtc.SourceFilePath(ctx),
106				Output:      p.timestampFilePath(ctx),
107				Implicit:    schema,
108				Args: map[string]string{
109					"xsd": schema.String(),
110				},
111			})
112			break
113		default:
114			ctx.PropertyErrorf("schema", "not supported extension: %q", schema.Ext())
115		}
116	} else {
117		// when schema is not specified, just check if the xml is well-formed
118		ctx.Build(pctx, android.BuildParams{
119			Rule:        xmllintMinimal,
120			Description: "xmllint-minimal",
121			Input:       p.PrebuiltEtc.SourceFilePath(ctx),
122			Output:      p.timestampFilePath(ctx),
123		})
124	}
125
126	p.SetAdditionalDependencies([]android.Path{p.timestampFilePath(ctx)})
127}
128
129func PrebuiltEtcXmlFactory() android.Module {
130	module := &prebuiltEtcXml{}
131	module.AddProperties(&module.properties)
132	etc.InitPrebuiltEtcModule(&module.PrebuiltEtc, "etc")
133	// This module is device-only
134	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
135	android.InitBazelModule(module)
136	return module
137}
138
139type bazelPrebuiltEtcXmlAttributes struct {
140	Src               bazel.LabelAttribute
141	Filename          bazel.LabelAttribute
142	Dir               string
143	Installable       bazel.BoolAttribute
144	Filename_from_src bazel.BoolAttribute
145	Schema            *string
146}
147
148func (p *prebuiltEtcXml) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
149	baseAttrs := p.PrebuiltEtc.Bp2buildHelper(ctx)
150
151	var schema *string
152	if p.properties.Schema != nil {
153		schema = p.properties.Schema
154	}
155
156	attrs := &bazelPrebuiltEtcXmlAttributes{
157		Src:               baseAttrs.Src,
158		Filename:          baseAttrs.Filename,
159		Dir:               baseAttrs.Dir,
160		Installable:       baseAttrs.Installable,
161		Filename_from_src: baseAttrs.Filename_from_src,
162		Schema:            schema,
163	}
164
165	props := bazel.BazelTargetModuleProperties{
166		Rule_class:        "prebuilt_xml",
167		Bzl_load_location: "//build/bazel/rules/prebuilt_xml.bzl",
168	}
169
170	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: p.Name()}, attrs)
171}
172