blob: a2297f48c8fd7033887938bf0a903858d3890951 [file] [log] [blame]
Dan Willemsen2902fa72017-04-27 21:16:35 -07001// Copyright 2017 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 main
16
17import (
18 "encoding/xml"
19 "flag"
20 "fmt"
21 "io"
22 "io/ioutil"
23 "os"
24 "path/filepath"
25 "regexp"
26 "sort"
27 "strings"
28 "text/template"
29
30 "github.com/google/blueprint/proptools"
31)
32
33type RewriteNames []RewriteName
34type RewriteName struct {
35 regexp *regexp.Regexp
36 repl string
37}
38
39func (r *RewriteNames) String() string {
40 return ""
41}
42
43func (r *RewriteNames) Set(v string) error {
44 split := strings.SplitN(v, "=", 2)
45 if len(split) != 2 {
46 return fmt.Errorf("Must be in the form of <regex>=<replace>")
47 }
48 regex, err := regexp.Compile(split[0])
49 if err != nil {
50 return nil
51 }
52 *r = append(*r, RewriteName{
53 regexp: regex,
54 repl: split[1],
55 })
56 return nil
57}
58
59func (r *RewriteNames) Rewrite(name string) string {
60 for _, r := range *r {
61 if r.regexp.MatchString(name) {
62 return r.regexp.ReplaceAllString(name, r.repl)
63 }
64 }
65 return name
66}
67
68var rewriteNames = RewriteNames{}
69
70type ExtraDeps map[string][]string
71
72func (d ExtraDeps) String() string {
73 return ""
74}
75
76func (d ExtraDeps) Set(v string) error {
77 split := strings.SplitN(v, "=", 2)
78 if len(split) != 2 {
79 return fmt.Errorf("Must be in the form of <module>=<module>[,<module>]")
80 }
81 d[split[0]] = strings.Split(split[1], ",")
82 return nil
83}
84
85var extraDeps = make(ExtraDeps)
86
Dan Willemsen47e44a42017-10-05 13:28:16 -070087var useVersion string
88
Dan Willemsen2902fa72017-04-27 21:16:35 -070089type Dependency struct {
90 XMLName xml.Name `xml:"dependency"`
91
92 GroupId string `xml:"groupId"`
93 ArtifactId string `xml:"artifactId"`
94 Version string `xml:"version"`
95 Type string `xml:"type"`
96
97 Scope string `xml:"scope"`
98}
99
100type Pom struct {
101 XMLName xml.Name `xml:"http://maven.apache.org/POM/4.0.0 project"`
102
103 ArtifactFile string `xml:"-"`
104
105 GroupId string `xml:"groupId"`
106 ArtifactId string `xml:"artifactId"`
107 Version string `xml:"version"`
108 Packaging string `xml:"packaging"`
109
110 Dependencies []Dependency `xml:"dependencies>dependency"`
111}
112
113func (p Pom) MkName() string {
114 return rewriteNames.Rewrite(p.ArtifactId)
115}
116
117func (p Pom) MkDeps() []string {
118 var ret []string
119 for _, d := range p.Dependencies {
120 if d.Type != "aar" {
121 continue
122 }
123 name := rewriteNames.Rewrite(d.ArtifactId)
124 ret = append(ret, name)
125 ret = append(ret, extraDeps[name]...)
126 }
127 return ret
128}
129
130var mkTemplate = template.Must(template.New("mk").Parse(`
131include $(CLEAR_VARS)
132LOCAL_MODULE := {{.MkName}}
133LOCAL_MODULE_CLASS := JAVA_LIBRARIES
134LOCAL_UNINSTALLABLE_MODULE := true
135LOCAL_SRC_FILES := {{.ArtifactFile}}
136LOCAL_BUILT_MODULE_STEM := javalib.jar
137LOCAL_MODULE_SUFFIX := .{{.Packaging}}
138LOCAL_USE_AAPT2 := true
139LOCAL_STATIC_ANDROID_LIBRARIES := \
140{{range .MkDeps}} {{.}} \
141{{end}}
142include $(BUILD_PREBUILT)
143`))
144
145func convert(filename string, out io.Writer) error {
146 data, err := ioutil.ReadFile(filename)
147 if err != nil {
148 return err
149 }
150
151 var pom Pom
152 err = xml.Unmarshal(data, &pom)
153 if err != nil {
154 return err
155 }
156
Dan Willemsen47e44a42017-10-05 13:28:16 -0700157 if useVersion != "" && pom.Version != useVersion {
158 return nil
159 }
160
Dan Willemsen2902fa72017-04-27 21:16:35 -0700161 if pom.Packaging == "" {
162 pom.Packaging = "jar"
163 }
164
165 pom.ArtifactFile = strings.TrimSuffix(filename, ".pom") + "." + pom.Packaging
166
167 return mkTemplate.Execute(out, pom)
168}
169
170func main() {
171 flag.Usage = func() {
172 fmt.Fprintf(os.Stderr, `pom2mk, a tool to create Android.mk files from maven repos
173
174The tool will extract the necessary information from *.pom files to create an Android.mk whose
175aar libraries can be linked against when using AAPT2.
176
177Usage: %s [--rewrite <regex>=<replace>] [--extra-deps <module>=<module>[,<module>]] <dir>
178
179 -rewrite <regex>=<replace>
180 rewrite can be used to specify mappings between the artifactId in the pom files and module
181 names in the Android.mk files. This can be specified multiple times, the first matching
182 regex will be used.
183 -extra-deps <module>=<module>[,<module>]
184 Some Android.mk modules have transitive dependencies that must be specified when they are
185 depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
186 This may be specified multiple times to declare these dependencies.
Dan Willemsen47e44a42017-10-05 13:28:16 -0700187 -use-version <version>
188 If the maven directory contains multiple versions of artifacts and their pom files,
189 -use-version can be used to only write makefiles for a specific version of those artifacts.
Dan Willemsen2902fa72017-04-27 21:16:35 -0700190 <dir>
191 The directory to search for *.pom files under.
192
193The makefile is written to stdout, to be put in the current directory (often as Android.mk)
194`, os.Args[0])
195 }
196
197 flag.Var(&extraDeps, "extra-deps", "Extra dependencies needed when depending on a module")
198 flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
Dan Willemsen47e44a42017-10-05 13:28:16 -0700199 flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
Dan Willemsen2902fa72017-04-27 21:16:35 -0700200 flag.Parse()
201
202 if flag.NArg() != 1 {
203 flag.Usage()
204 os.Exit(1)
205 }
206
207 dir := flag.Arg(0)
208 absDir, err := filepath.Abs(dir)
209 if err != nil {
210 fmt.Println(os.Stderr, "Failed to get absolute directory:", err)
211 os.Exit(1)
212 }
213
214 var filenames []string
215 err = filepath.Walk(absDir, func(path string, info os.FileInfo, err error) error {
216 if err != nil {
217 return err
218 }
219
220 name := info.Name()
221 if info.IsDir() {
222 if strings.HasPrefix(name, ".") {
223 return filepath.SkipDir
224 }
225 return nil
226 }
227
228 if strings.HasPrefix(name, ".") {
229 return nil
230 }
231
232 if strings.HasSuffix(name, ".pom") {
233 path, err = filepath.Rel(absDir, path)
234 if err != nil {
235 return err
236 }
237 filenames = append(filenames, filepath.Join(dir, path))
238 }
239 return nil
240 })
241 if err != nil {
242 fmt.Fprintln(os.Stderr, "Error walking files:", err)
243 os.Exit(1)
244 }
245
246 if len(filenames) == 0 {
247 fmt.Fprintln(os.Stderr, "Error: no *.pom files found under", dir)
248 os.Exit(1)
249 }
250
251 sort.Strings(filenames)
252
253 fmt.Println("# Automatically generated with:")
254 fmt.Println("# pom2mk", strings.Join(proptools.ShellEscape(os.Args[1:]), " "))
255 fmt.Println("LOCAL_PATH := $(call my-dir)")
256
257 for _, filename := range filenames {
258 err := convert(filename, os.Stdout)
259 if err != nil {
260 fmt.Fprintln(os.Stderr, "Error converting", filename, err)
261 os.Exit(1)
262 }
263 }
264}