Home | History | Annotate | Download | only in pom2mk
      1 // 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 
     15 package main
     16 
     17 import (
     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 
     33 type RewriteNames []RewriteName
     34 type RewriteName struct {
     35 	regexp *regexp.Regexp
     36 	repl   string
     37 }
     38 
     39 func (r *RewriteNames) String() string {
     40 	return ""
     41 }
     42 
     43 func (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 
     59 func (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 
     68 var rewriteNames = RewriteNames{}
     69 
     70 type ExtraDeps map[string][]string
     71 
     72 func (d ExtraDeps) String() string {
     73 	return ""
     74 }
     75 
     76 func (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 
     85 var extraDeps = make(ExtraDeps)
     86 
     87 type Dependency struct {
     88 	XMLName xml.Name `xml:"dependency"`
     89 
     90 	GroupId    string `xml:"groupId"`
     91 	ArtifactId string `xml:"artifactId"`
     92 	Version    string `xml:"version"`
     93 	Type       string `xml:"type"`
     94 
     95 	Scope string `xml:"scope"`
     96 }
     97 
     98 type Pom struct {
     99 	XMLName xml.Name `xml:"http://maven.apache.org/POM/4.0.0 project"`
    100 
    101 	ArtifactFile string `xml:"-"`
    102 
    103 	GroupId    string `xml:"groupId"`
    104 	ArtifactId string `xml:"artifactId"`
    105 	Version    string `xml:"version"`
    106 	Packaging  string `xml:"packaging"`
    107 
    108 	Dependencies []Dependency `xml:"dependencies>dependency"`
    109 }
    110 
    111 func (p Pom) MkName() string {
    112 	return rewriteNames.Rewrite(p.ArtifactId)
    113 }
    114 
    115 func (p Pom) MkDeps() []string {
    116 	var ret []string
    117 	for _, d := range p.Dependencies {
    118 		if d.Type != "aar" {
    119 			continue
    120 		}
    121 		name := rewriteNames.Rewrite(d.ArtifactId)
    122 		ret = append(ret, name)
    123 		ret = append(ret, extraDeps[name]...)
    124 	}
    125 	return ret
    126 }
    127 
    128 var mkTemplate = template.Must(template.New("mk").Parse(`
    129 include $(CLEAR_VARS)
    130 LOCAL_MODULE := {{.MkName}}
    131 LOCAL_MODULE_CLASS := JAVA_LIBRARIES
    132 LOCAL_UNINSTALLABLE_MODULE := true
    133 LOCAL_SRC_FILES := {{.ArtifactFile}}
    134 LOCAL_BUILT_MODULE_STEM := javalib.jar
    135 LOCAL_MODULE_SUFFIX := .{{.Packaging}}
    136 LOCAL_USE_AAPT2 := true
    137 LOCAL_STATIC_ANDROID_LIBRARIES := \
    138 {{range .MkDeps}}  {{.}} \
    139 {{end}}
    140 include $(BUILD_PREBUILT)
    141 `))
    142 
    143 func convert(filename string, out io.Writer) error {
    144 	data, err := ioutil.ReadFile(filename)
    145 	if err != nil {
    146 		return err
    147 	}
    148 
    149 	var pom Pom
    150 	err = xml.Unmarshal(data, &pom)
    151 	if err != nil {
    152 		return err
    153 	}
    154 
    155 	if pom.Packaging == "" {
    156 		pom.Packaging = "jar"
    157 	}
    158 
    159 	pom.ArtifactFile = strings.TrimSuffix(filename, ".pom") + "." + pom.Packaging
    160 
    161 	return mkTemplate.Execute(out, pom)
    162 }
    163 
    164 func main() {
    165 	flag.Usage = func() {
    166 		fmt.Fprintf(os.Stderr, `pom2mk, a tool to create Android.mk files from maven repos
    167 
    168 The tool will extract the necessary information from *.pom files to create an Android.mk whose
    169 aar libraries can be linked against when using AAPT2.
    170 
    171 Usage: %s [--rewrite <regex>=<replace>] [--extra-deps <module>=<module>[,<module>]] <dir>
    172 
    173   -rewrite <regex>=<replace>
    174      rewrite can be used to specify mappings between the artifactId in the pom files and module
    175      names in the Android.mk files. This can be specified multiple times, the first matching
    176      regex will be used.
    177   -extra-deps <module>=<module>[,<module>]
    178      Some Android.mk modules have transitive dependencies that must be specified when they are
    179      depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
    180      This may be specified multiple times to declare these dependencies.
    181   <dir>
    182      The directory to search for *.pom files under.
    183 
    184 The makefile is written to stdout, to be put in the current directory (often as Android.mk)
    185 `, os.Args[0])
    186 	}
    187 
    188 	flag.Var(&extraDeps, "extra-deps", "Extra dependencies needed when depending on a module")
    189 	flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
    190 	flag.Parse()
    191 
    192 	if flag.NArg() != 1 {
    193 		flag.Usage()
    194 		os.Exit(1)
    195 	}
    196 
    197 	dir := flag.Arg(0)
    198 	absDir, err := filepath.Abs(dir)
    199 	if err != nil {
    200 		fmt.Println(os.Stderr, "Failed to get absolute directory:", err)
    201 		os.Exit(1)
    202 	}
    203 
    204 	var filenames []string
    205 	err = filepath.Walk(absDir, func(path string, info os.FileInfo, err error) error {
    206 		if err != nil {
    207 			return err
    208 		}
    209 
    210 		name := info.Name()
    211 		if info.IsDir() {
    212 			if strings.HasPrefix(name, ".") {
    213 				return filepath.SkipDir
    214 			}
    215 			return nil
    216 		}
    217 
    218 		if strings.HasPrefix(name, ".") {
    219 			return nil
    220 		}
    221 
    222 		if strings.HasSuffix(name, ".pom") {
    223 			path, err = filepath.Rel(absDir, path)
    224 			if err != nil {
    225 				return err
    226 			}
    227 			filenames = append(filenames, filepath.Join(dir, path))
    228 		}
    229 		return nil
    230 	})
    231 	if err != nil {
    232 		fmt.Fprintln(os.Stderr, "Error walking files:", err)
    233 		os.Exit(1)
    234 	}
    235 
    236 	if len(filenames) == 0 {
    237 		fmt.Fprintln(os.Stderr, "Error: no *.pom files found under", dir)
    238 		os.Exit(1)
    239 	}
    240 
    241 	sort.Strings(filenames)
    242 
    243 	fmt.Println("# Automatically generated with:")
    244 	fmt.Println("# pom2mk", strings.Join(proptools.ShellEscape(os.Args[1:]), " "))
    245 	fmt.Println("LOCAL_PATH := $(call my-dir)")
    246 
    247 	for _, filename := range filenames {
    248 		err := convert(filename, os.Stdout)
    249 		if err != nil {
    250 			fmt.Fprintln(os.Stderr, "Error converting", filename, err)
    251 			os.Exit(1)
    252 		}
    253 	}
    254 }
    255