blob: 49cc93119485b9dc483e49d0c0530fcee19a0882 [file] [log] [blame]
Jiyong Park58c518b2018-05-12 22:29:12 +09001// 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 java
16
17import (
18 "android/soong/android"
19 "sort"
Jiyong Park58c518b2018-05-12 22:29:12 +090020 "strings"
21
22 "github.com/google/blueprint/proptools"
23)
24
25// prebuilt_apis is a meta-module that generates filegroup modules for all
26// API txt files found under the directory where the Android.bp is located.
27// Specificaly, an API file located at ./<ver>/<scope>/api/<module>.txt
28// generates a filegroup module named <module>-api.<scope>.<ver>.
29//
30// It also creates <module>-api.<scope>.latest for the lastest <ver>.
31//
32func init() {
Inseob Kimc0907f12019-02-08 21:00:45 +090033 android.RegisterModuleType("prebuilt_apis", PrebuiltApisFactory)
Jiyong Park58c518b2018-05-12 22:29:12 +090034
35 android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
Inseob Kimc0907f12019-02-08 21:00:45 +090036 ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
Jiyong Park58c518b2018-05-12 22:29:12 +090037 })
38}
39
Sundong Ahn27eecb92018-06-21 13:47:17 +090040type prebuiltApisProperties struct {
41 // list of api version directories
42 Api_dirs []string
43}
44
Jiyong Park58c518b2018-05-12 22:29:12 +090045type prebuiltApis struct {
46 android.ModuleBase
Sundong Ahn27eecb92018-06-21 13:47:17 +090047 properties prebuiltApisProperties
Jiyong Park58c518b2018-05-12 22:29:12 +090048}
49
Jiyong Park58c518b2018-05-12 22:29:12 +090050func (module *prebuiltApis) GenerateAndroidBuildActions(ctx android.ModuleContext) {
51 // no need to implement
52}
53
Sundong Ahna01c2a52018-06-07 21:42:16 +090054func parseJarPath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
55 elements := strings.Split(path, "/")
56
57 apiver = elements[0]
58 scope = elements[1]
Sundong Ahna01c2a52018-06-07 21:42:16 +090059
60 module = strings.TrimSuffix(elements[2], ".jar")
61 return
62}
63
Sundong Ahn054b19a2018-10-19 13:46:09 +090064func parseApiFilePath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
Jiyong Park58c518b2018-05-12 22:29:12 +090065 elements := strings.Split(path, "/")
Sundong Ahn054b19a2018-10-19 13:46:09 +090066 apiver = elements[0]
Jiyong Park58c518b2018-05-12 22:29:12 +090067
68 scope = elements[1]
69 if scope != "public" && scope != "system" && scope != "test" {
70 ctx.ModuleErrorf("invalid scope %q found in path: %q", scope, path)
71 return
72 }
73
74 // elements[2] is string literal "api". skipping.
75 module = strings.TrimSuffix(elements[3], ".txt")
76 return
77}
78
Sundong Ahna01c2a52018-06-07 21:42:16 +090079func createImport(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
80 props := struct {
81 Name *string
82 Jars []string
83 Sdk_version *string
84 Installable *bool
85 }{}
Sundong Ahn27eecb92018-06-21 13:47:17 +090086 props.Name = proptools.StringPtr(mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module)
Sundong Ahna01c2a52018-06-07 21:42:16 +090087 props.Jars = append(props.Jars, path)
88 // TODO(hansson): change to scope after migration is done.
89 props.Sdk_version = proptools.StringPtr("current")
90 props.Installable = proptools.BoolPtr(false)
91
92 mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props)
93}
94
Jiyong Park58c518b2018-05-12 22:29:12 +090095func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
96 fgName := module + ".api." + scope + "." + apiver
97 filegroupProps := struct {
98 Name *string
99 Srcs []string
100 }{}
101 filegroupProps.Name = proptools.StringPtr(fgName)
102 filegroupProps.Srcs = []string{path}
103 mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &filegroupProps)
104}
105
Sundong Ahna01c2a52018-06-07 21:42:16 +0900106func prebuiltSdkStubs(mctx android.TopDownMutatorContext) {
107 mydir := mctx.ModuleDir() + "/"
108 // <apiver>/<scope>/<module>.jar
Sundong Ahn27eecb92018-06-21 13:47:17 +0900109 var files []string
110 for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
111 for _, scope := range []string{"public", "system", "test", "core"} {
112 vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"*/*.jar", nil)
113 if err != nil {
114 mctx.ModuleErrorf("failed to glob jar files under %q: %s", mydir+apiver+"/"+scope, err)
115 }
116 files = append(files, vfiles...)
117 }
Sundong Ahna01c2a52018-06-07 21:42:16 +0900118 }
119
120 for _, f := range files {
121 // create a Import module for each jar file
122 localPath := strings.TrimPrefix(f, mydir)
123 module, apiver, scope := parseJarPath(mctx, localPath)
Sundong Ahn27eecb92018-06-21 13:47:17 +0900124 createImport(mctx, module, scope, apiver, localPath)
Sundong Ahna01c2a52018-06-07 21:42:16 +0900125 }
126}
127
128func prebuiltApiFiles(mctx android.TopDownMutatorContext) {
129 mydir := mctx.ModuleDir() + "/"
130 // <apiver>/<scope>/api/<module>.txt
131 files, err := mctx.GlobWithDeps(mydir+"*/*/api/*.txt", nil)
132 if err != nil {
133 mctx.ModuleErrorf("failed to glob api txt files under %q: %s", mydir, err)
134 }
135 if len(files) == 0 {
136 mctx.ModuleErrorf("no api file found under %q", mydir)
137 }
138
139 // construct a map to find out the latest api file path
140 // for each (<module>, <scope>) pair.
141 type latestApiInfo struct {
142 module string
143 scope string
Sundong Ahn054b19a2018-10-19 13:46:09 +0900144 apiver string
Sundong Ahna01c2a52018-06-07 21:42:16 +0900145 path string
146 }
147 m := make(map[string]latestApiInfo)
148
149 for _, f := range files {
150 // create a filegroup for each api txt file
151 localPath := strings.TrimPrefix(f, mydir)
152 module, apiver, scope := parseApiFilePath(mctx, localPath)
Sundong Ahn054b19a2018-10-19 13:46:09 +0900153 createFilegroup(mctx, module, scope, apiver, localPath)
Sundong Ahna01c2a52018-06-07 21:42:16 +0900154
155 // find the latest apiver
156 key := module + "." + scope
157 info, ok := m[key]
158 if !ok {
159 m[key] = latestApiInfo{module, scope, apiver, localPath}
Sundong Ahn054b19a2018-10-19 13:46:09 +0900160 } else if len(apiver) > len(info.apiver) || (len(apiver) == len(info.apiver) &&
161 strings.Compare(apiver, info.apiver) > 0) {
Sundong Ahna01c2a52018-06-07 21:42:16 +0900162 info.apiver = apiver
163 info.path = localPath
164 }
165 }
166 // create filegroups for the latest version of (<module>, <scope>) pairs
167 // sort the keys in order to make build.ninja stable
168 keys := make([]string, 0, len(m))
169 for k := range m {
170 keys = append(keys, k)
171 }
172 sort.Strings(keys)
173 for _, k := range keys {
174 info := m[k]
175 createFilegroup(mctx, info.module, info.scope, "latest", info.path)
176 }
177}
178
Inseob Kimc0907f12019-02-08 21:00:45 +0900179func PrebuiltApisMutator(mctx android.TopDownMutatorContext) {
Jiyong Park58c518b2018-05-12 22:29:12 +0900180 if _, ok := mctx.Module().(*prebuiltApis); ok {
Sundong Ahna01c2a52018-06-07 21:42:16 +0900181 prebuiltApiFiles(mctx)
182 prebuiltSdkStubs(mctx)
Jiyong Park58c518b2018-05-12 22:29:12 +0900183 }
184}
185
Inseob Kimc0907f12019-02-08 21:00:45 +0900186func PrebuiltApisFactory() android.Module {
Jiyong Park58c518b2018-05-12 22:29:12 +0900187 module := &prebuiltApis{}
Sundong Ahn27eecb92018-06-21 13:47:17 +0900188 module.AddProperties(&module.properties)
Jiyong Park58c518b2018-05-12 22:29:12 +0900189 android.InitAndroidModule(module)
190 return module
191}