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 xsdc
16
17import (
18	"android/soong/android"
19	"android/soong/java"
20	"path/filepath"
21	"strings"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/proptools"
25)
26
27func init() {
28	pctx.Import("android/soong/java/config")
29	android.RegisterModuleType("xsd_config", xsdConfigFactory)
30
31	android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
32		ctx.TopDown("xsd_config", xsdConfigMutator).Parallel()
33	})
34}
35
36var (
37	pctx = android.NewPackageContext("android/xsdc")
38
39	xsdc         = pctx.HostBinToolVariable("xsdcCmd", "xsdc")
40	xsdcJavaRule = pctx.StaticRule("xsdcJavaRule", blueprint.RuleParams{
41		Command: `rm -rf "${out}.temp" && mkdir -p "${out}.temp" && ` +
42			`${xsdcCmd} $in -p $pkgName -o ${out}.temp -j $args && ` +
43			`${config.SoongZipCmd} -jar -o ${out} -C ${out}.temp -D ${out}.temp && ` +
44			`rm -rf ${out}.temp`,
45		CommandDeps: []string{"${xsdcCmd}", "${config.SoongZipCmd}"},
46		Description: "xsdc Java ${in} => ${out}",
47	}, "pkgName", "args")
48
49	xsdcCppRule = pctx.StaticRule("xsdcCppRule", blueprint.RuleParams{
50		Command: `rm -rf "${outDir}" && ` +
51			`${xsdcCmd} $in -p $pkgName -o ${outDir} -c $args`,
52		CommandDeps: []string{"${xsdcCmd}", "${config.SoongZipCmd}"},
53		Description: "xsdc C++ ${in} => ${out}",
54	}, "pkgName", "outDir", "args")
55
56	xsdConfigRule = pctx.StaticRule("xsdConfigRule", blueprint.RuleParams{
57		Command:     "cp -f ${in} ${output}",
58		Description: "copy the xsd file: ${in} => ${output}",
59	}, "output")
60)
61
62type xsdConfigProperties struct {
63	Srcs         []string
64	Package_name *string
65	Api_dir      *string
66	Gen_writer   *bool
67}
68
69type xsdConfig struct {
70	android.ModuleBase
71
72	properties xsdConfigProperties
73
74	genOutputDir android.Path
75	genOutputs_j android.WritablePath
76	genOutputs_c android.WritablePath
77	genOutputs_h android.WritablePath
78
79	docsPath android.Path
80
81	xsdConfigPath android.OptionalPath
82	genOutputs  android.Paths
83}
84
85var _ android.SourceFileProducer = (*xsdConfig)(nil)
86
87type ApiToCheck struct {
88	Api_file         *string
89	Removed_api_file *string
90	Args             *string
91}
92
93type CheckApi struct {
94	Last_released ApiToCheck
95	Current       ApiToCheck
96}
97type DroidstubsProperties struct {
98	Name                 *string
99	Installable          *bool
100	Srcs                 []string
101	Sdk_version          *string
102	Args                 *string
103	Api_filename         *string
104	Removed_api_filename *string
105	Check_api            CheckApi
106}
107
108func (module *xsdConfig) GeneratedSourceFiles() android.Paths {
109	return android.Paths{module.genOutputs_c}
110}
111
112func (module *xsdConfig) Srcs() android.Paths {
113	return append(module.genOutputs, module.genOutputs_j)
114}
115
116func (module *xsdConfig) GeneratedDeps() android.Paths {
117	return android.Paths{module.genOutputs_h}
118}
119
120func (module *xsdConfig) GeneratedHeaderDirs() android.Paths {
121	return android.Paths{module.genOutputDir}
122}
123
124func (module *xsdConfig) DepsMutator(ctx android.BottomUpMutatorContext) {
125	android.ExtractSourcesDeps(ctx, module.properties.Srcs)
126}
127
128func (module *xsdConfig) generateXsdConfig(ctx android.ModuleContext) {
129	if !module.xsdConfigPath.Valid() {
130		return
131	}
132
133	output := android.PathForModuleGen(ctx, module.Name()+".xsd")
134	module.genOutputs = append(module.genOutputs, output)
135
136	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
137		Rule:   xsdConfigRule,
138		Input:  module.xsdConfigPath.Path(),
139		Output: output,
140		Args: map[string]string{
141			"output": output.String(),
142		},
143	})
144}
145
146func (module *xsdConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
147	if len(module.properties.Srcs) != 1 {
148		ctx.PropertyErrorf("srcs", "xsd_config must be one src")
149	}
150
151	ctx.VisitDirectDeps(func(to android.Module) {
152		if doc, ok := to.(java.ApiFilePath); ok {
153			module.docsPath = doc.ApiFilePath()
154		}
155	})
156
157	srcFiles := ctx.ExpandSources(module.properties.Srcs, nil)
158	xsdFile := srcFiles[0]
159
160	pkgName := *module.properties.Package_name
161	filenameStem := strings.Replace(pkgName, ".", "_", -1)
162
163	args := ""
164	if proptools.Bool(module.properties.Gen_writer) {
165		args = "-w"
166	}
167
168	module.genOutputs_j = android.PathForModuleGen(ctx, "java", filenameStem+"_xsdcgen.srcjar")
169
170	ctx.Build(pctx, android.BuildParams{
171		Rule:        xsdcJavaRule,
172		Description: "xsdc " + xsdFile.String(),
173		Input:       xsdFile,
174		Implicit:    module.docsPath,
175		Output:      module.genOutputs_j,
176		Args: map[string]string{
177			"pkgName": pkgName,
178			"args": args,
179		},
180	})
181
182	module.genOutputs_c = android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp")
183	module.genOutputs_h = android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h")
184	module.genOutputDir = android.PathForModuleGen(ctx, "cpp", "include")
185
186	ctx.Build(pctx, android.BuildParams{
187		Rule:           xsdcCppRule,
188		Description:    "xsdc " + xsdFile.String(),
189		Input:          xsdFile,
190		Implicit:       module.docsPath,
191		Output:         module.genOutputs_c,
192		ImplicitOutput: module.genOutputs_h,
193		Args: map[string]string{
194			"pkgName": pkgName,
195			"outDir":  android.PathForModuleGen(ctx, "cpp").String(),
196			"args": args,
197		},
198	})
199	module.xsdConfigPath = android.ExistentPathForSource(ctx, xsdFile.String())
200	module.generateXsdConfig(ctx)
201}
202
203func xsdConfigMutator(mctx android.TopDownMutatorContext) {
204	if module, ok := mctx.Module().(*xsdConfig); ok {
205		name := module.BaseModuleName()
206
207		args := " --stub-packages " + *module.properties.Package_name +
208			" --hide MissingPermission --hide BroadcastBehavior" +
209			" --hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol" +
210			" --hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
211
212		api_dir := proptools.StringDefault(module.properties.Api_dir, "api")
213
214		currentApiFileName := filepath.Join(api_dir, "current.txt")
215		removedApiFileName := filepath.Join(api_dir, "removed.txt")
216
217		check_api := CheckApi{}
218
219		check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
220		check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
221
222		check_api.Last_released.Api_file = proptools.StringPtr(
223			filepath.Join(api_dir, "last_current.txt"))
224		check_api.Last_released.Removed_api_file = proptools.StringPtr(
225			filepath.Join(api_dir, "last_removed.txt"))
226
227		mctx.CreateModule(java.DroidstubsFactory, &DroidstubsProperties{
228			Name:                 proptools.StringPtr(name + ".docs"),
229			Srcs:                 []string{":" + name},
230			Args:                 proptools.StringPtr(args),
231			Api_filename:         proptools.StringPtr(currentApiFileName),
232			Removed_api_filename: proptools.StringPtr(removedApiFileName),
233			Check_api:            check_api,
234			Installable:          proptools.BoolPtr(false),
235			Sdk_version:          proptools.StringPtr("core_platform"),
236		})
237	}
238}
239
240func xsdConfigFactory() android.Module {
241	module := &xsdConfig{}
242	module.AddProperties(&module.properties)
243	android.InitAndroidModule(module)
244
245	return module
246}
247