pom2bp.go 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  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. package main
  15. import (
  16. "archive/zip"
  17. "bufio"
  18. "bytes"
  19. "encoding/xml"
  20. "flag"
  21. "fmt"
  22. "io/ioutil"
  23. "os"
  24. "os/exec"
  25. "path"
  26. "path/filepath"
  27. "regexp"
  28. "sort"
  29. "strings"
  30. "text/template"
  31. "github.com/google/blueprint/proptools"
  32. "android/soong/bpfix/bpfix"
  33. )
  34. type RewriteNames []RewriteName
  35. type RewriteName struct {
  36. regexp *regexp.Regexp
  37. repl string
  38. }
  39. func (r *RewriteNames) String() string {
  40. return ""
  41. }
  42. func (r *RewriteNames) Set(v string) error {
  43. split := strings.SplitN(v, "=", 2)
  44. if len(split) != 2 {
  45. return fmt.Errorf("Must be in the form of <regex>=<replace>")
  46. }
  47. regex, err := regexp.Compile(split[0])
  48. if err != nil {
  49. return nil
  50. }
  51. *r = append(*r, RewriteName{
  52. regexp: regex,
  53. repl: split[1],
  54. })
  55. return nil
  56. }
  57. func (r *RewriteNames) MavenToBp(groupId string, artifactId string) string {
  58. for _, r := range *r {
  59. if r.regexp.MatchString(groupId + ":" + artifactId) {
  60. return r.regexp.ReplaceAllString(groupId+":"+artifactId, r.repl)
  61. } else if r.regexp.MatchString(artifactId) {
  62. return r.regexp.ReplaceAllString(artifactId, r.repl)
  63. }
  64. }
  65. return artifactId
  66. }
  67. var rewriteNames = RewriteNames{}
  68. type ExtraDeps map[string][]string
  69. func (d ExtraDeps) String() string {
  70. return ""
  71. }
  72. func (d ExtraDeps) Set(v string) error {
  73. split := strings.SplitN(v, "=", 2)
  74. if len(split) != 2 {
  75. return fmt.Errorf("Must be in the form of <module>=<module>[,<module>]")
  76. }
  77. d[split[0]] = strings.Split(split[1], ",")
  78. return nil
  79. }
  80. var extraStaticLibs = make(ExtraDeps)
  81. var extraLibs = make(ExtraDeps)
  82. var optionalUsesLibs = make(ExtraDeps)
  83. type Exclude map[string]bool
  84. func (e Exclude) String() string {
  85. return ""
  86. }
  87. func (e Exclude) Set(v string) error {
  88. e[v] = true
  89. return nil
  90. }
  91. var excludes = make(Exclude)
  92. type HostModuleNames map[string]bool
  93. func (n HostModuleNames) IsHostModule(groupId string, artifactId string) bool {
  94. _, found := n[groupId+":"+artifactId]
  95. return found
  96. }
  97. func (n HostModuleNames) String() string {
  98. return ""
  99. }
  100. func (n HostModuleNames) Set(v string) error {
  101. n[v] = true
  102. return nil
  103. }
  104. var hostModuleNames = HostModuleNames{}
  105. type HostAndDeviceModuleNames map[string]bool
  106. func (n HostAndDeviceModuleNames) IsHostAndDeviceModule(groupId string, artifactId string) bool {
  107. _, found := n[groupId+":"+artifactId]
  108. return found
  109. }
  110. func (n HostAndDeviceModuleNames) String() string {
  111. return ""
  112. }
  113. func (n HostAndDeviceModuleNames) Set(v string) error {
  114. n[v] = true
  115. return nil
  116. }
  117. var hostAndDeviceModuleNames = HostAndDeviceModuleNames{}
  118. var sdkVersion string
  119. var defaultMinSdkVersion string
  120. var useVersion string
  121. var staticDeps bool
  122. var writeCmd bool
  123. var jetifier bool
  124. func InList(s string, list []string) bool {
  125. for _, l := range list {
  126. if l == s {
  127. return true
  128. }
  129. }
  130. return false
  131. }
  132. type Dependency struct {
  133. XMLName xml.Name `xml:"dependency"`
  134. BpTarget string `xml:"-"`
  135. BazelTarget string `xml:"-"`
  136. GroupId string `xml:"groupId"`
  137. ArtifactId string `xml:"artifactId"`
  138. Version string `xml:"version"`
  139. Type string `xml:"type"`
  140. Scope string `xml:"scope"`
  141. }
  142. func (d Dependency) BpName() string {
  143. if d.BpTarget == "" {
  144. d.BpTarget = rewriteNames.MavenToBp(d.GroupId, d.ArtifactId)
  145. }
  146. return d.BpTarget
  147. }
  148. type Pom struct {
  149. XMLName xml.Name `xml:"http://maven.apache.org/POM/4.0.0 project"`
  150. PomFile string `xml:"-"`
  151. ArtifactFile string `xml:"-"`
  152. BpTarget string `xml:"-"`
  153. MinSdkVersion string `xml:"-"`
  154. GroupId string `xml:"groupId"`
  155. ArtifactId string `xml:"artifactId"`
  156. Version string `xml:"version"`
  157. Packaging string `xml:"packaging"`
  158. Dependencies []*Dependency `xml:"dependencies>dependency"`
  159. }
  160. func (p Pom) IsAar() bool {
  161. return p.Packaging == "aar"
  162. }
  163. func (p Pom) IsJar() bool {
  164. return p.Packaging == "jar"
  165. }
  166. func (p Pom) IsApk() bool {
  167. return p.Packaging == "apk"
  168. }
  169. func (p Pom) IsHostModule() bool {
  170. return hostModuleNames.IsHostModule(p.GroupId, p.ArtifactId)
  171. }
  172. func (p Pom) IsDeviceModule() bool {
  173. return !p.IsHostModule()
  174. }
  175. func (p Pom) IsHostAndDeviceModule() bool {
  176. return hostAndDeviceModuleNames.IsHostAndDeviceModule(p.GroupId, p.ArtifactId)
  177. }
  178. func (p Pom) IsHostOnly() bool {
  179. return p.IsHostModule() && !p.IsHostAndDeviceModule()
  180. }
  181. func (p Pom) ModuleType() string {
  182. if p.IsAar() {
  183. return "android_library"
  184. } else if p.IsHostOnly() {
  185. return "java_library_host"
  186. } else {
  187. return "java_library_static"
  188. }
  189. }
  190. func (p Pom) BazelTargetType() string {
  191. if p.IsAar() {
  192. return "android_library"
  193. } else {
  194. return "java_library"
  195. }
  196. }
  197. func (p Pom) ImportModuleType() string {
  198. if p.IsAar() {
  199. return "android_library_import"
  200. } else if p.IsApk() {
  201. return "android_app_import"
  202. } else if p.IsHostOnly() {
  203. return "java_import_host"
  204. } else {
  205. return "java_import"
  206. }
  207. }
  208. func (p Pom) BazelImportTargetType() string {
  209. if p.IsAar() {
  210. return "aar_import"
  211. } else if p.IsApk() {
  212. return "apk_import"
  213. } else {
  214. return "java_import"
  215. }
  216. }
  217. func (p Pom) ImportProperty() string {
  218. if p.IsAar() {
  219. return "aars"
  220. } else if p.IsApk() {
  221. return "apk"
  222. } else {
  223. return "jars"
  224. }
  225. }
  226. func (p Pom) BazelImportProperty() string {
  227. if p.IsAar() {
  228. return "aar"
  229. } else if p.IsApk() {
  230. return "apk"
  231. } else {
  232. return "jars"
  233. }
  234. }
  235. func (p Pom) BpName() string {
  236. if p.BpTarget == "" {
  237. p.BpTarget = rewriteNames.MavenToBp(p.GroupId, p.ArtifactId)
  238. }
  239. return p.BpTarget
  240. }
  241. func (p Pom) BpJarDeps() []string {
  242. return p.BpDeps("jar", []string{"compile", "runtime"})
  243. }
  244. func (p Pom) BpAarDeps() []string {
  245. return p.BpDeps("aar", []string{"compile", "runtime"})
  246. }
  247. func (p Pom) BazelJarDeps() []string {
  248. return p.BazelDeps("jar", []string{"compile", "runtime"})
  249. }
  250. func (p Pom) BazelAarDeps() []string {
  251. return p.BazelDeps("aar", []string{"compile", "runtime"})
  252. }
  253. func (p Pom) BpExtraStaticLibs() []string {
  254. return extraStaticLibs[p.BpName()]
  255. }
  256. func (p Pom) BpExtraLibs() []string {
  257. return extraLibs[p.BpName()]
  258. }
  259. func (p Pom) BpOptionalUsesLibs() []string {
  260. return optionalUsesLibs[p.BpName()]
  261. }
  262. // BpDeps obtains dependencies filtered by type and scope. The results of this
  263. // method are formatted as Android.bp targets, e.g. run through MavenToBp rules.
  264. func (p Pom) BpDeps(typeExt string, scopes []string) []string {
  265. var ret []string
  266. for _, d := range p.Dependencies {
  267. if d.Type != typeExt || !InList(d.Scope, scopes) {
  268. continue
  269. }
  270. name := rewriteNames.MavenToBp(d.GroupId, d.ArtifactId)
  271. ret = append(ret, name)
  272. }
  273. return ret
  274. }
  275. // BazelDeps obtains dependencies filtered by type and scope. The results of this
  276. // method are formatted as Bazel BUILD targets.
  277. func (p Pom) BazelDeps(typeExt string, scopes []string) []string {
  278. var ret []string
  279. for _, d := range p.Dependencies {
  280. if d.Type != typeExt || !InList(d.Scope, scopes) {
  281. continue
  282. }
  283. ret = append(ret, d.BazelTarget)
  284. }
  285. return ret
  286. }
  287. func PathModVars() (string, string, string) {
  288. cmd := "/bin/bash"
  289. androidTop := os.Getenv("ANDROID_BUILD_TOP")
  290. envSetupSh := path.Join(androidTop, "build/envsetup.sh")
  291. return cmd, androidTop, envSetupSh
  292. }
  293. func InitRefreshMod(poms []*Pom) error {
  294. cmd, _, envSetupSh := PathModVars()
  295. // refreshmod is expensive, so if pathmod is already working we can skip it.
  296. _, err := exec.Command(cmd, "-c", ". "+envSetupSh+" && pathmod "+poms[0].BpName()).Output()
  297. if exitErr, _ := err.(*exec.ExitError); exitErr != nil || err != nil {
  298. _, err := exec.Command(cmd, "-c", ". "+envSetupSh+" && refreshmod").Output()
  299. if exitErr, _ := err.(*exec.ExitError); exitErr != nil {
  300. return fmt.Errorf("failed to run %s\n%s\ntry running lunch.", cmd, string(exitErr.Stderr))
  301. } else if err != nil {
  302. return err
  303. }
  304. }
  305. return nil
  306. }
  307. func BazelifyExtraDeps(extraDeps ExtraDeps, modules map[string]*Pom) error {
  308. for _, deps := range extraDeps {
  309. for _, dep := range deps {
  310. bazelName, err := BpNameToBazelTarget(dep, modules)
  311. if err != nil {
  312. return err
  313. }
  314. dep = bazelName
  315. }
  316. }
  317. return nil
  318. }
  319. func (p *Pom) GetBazelDepNames(modules map[string]*Pom) error {
  320. for _, d := range p.Dependencies {
  321. bazelName, err := BpNameToBazelTarget(d.BpName(), modules)
  322. if err != nil {
  323. return err
  324. }
  325. d.BazelTarget = bazelName
  326. }
  327. return nil
  328. }
  329. func BpNameToBazelTarget(bpName string, modules map[string]*Pom) (string, error) {
  330. cmd, androidTop, envSetupSh := PathModVars()
  331. if _, ok := modules[bpName]; ok {
  332. // We've seen the POM for this dependency, it will be local to the output BUILD file
  333. return ":" + bpName, nil
  334. } else {
  335. // we don't have the POM for this artifact, find and use the fully qualified target name.
  336. output, err := exec.Command(cmd, "-c", ". "+envSetupSh+" && pathmod "+bpName).Output()
  337. if exitErr, _ := err.(*exec.ExitError); exitErr != nil {
  338. return "", fmt.Errorf("failed to run %s %s\n%s", cmd, bpName, string(exitErr.Stderr))
  339. } else if err != nil {
  340. return "", err
  341. }
  342. relPath := ""
  343. for _, line := range strings.Fields(string(output)) {
  344. if strings.Contains(line, androidTop) {
  345. relPath = strings.TrimPrefix(line, androidTop)
  346. relPath = strings.TrimLeft(relPath, "/")
  347. }
  348. }
  349. return "//" + relPath + ":" + bpName, nil
  350. }
  351. }
  352. func (p Pom) SdkVersion() string {
  353. return sdkVersion
  354. }
  355. func (p Pom) DefaultMinSdkVersion() string {
  356. return defaultMinSdkVersion
  357. }
  358. func (p Pom) Jetifier() bool {
  359. return jetifier
  360. }
  361. func (p *Pom) FixDeps(modules map[string]*Pom) {
  362. for _, d := range p.Dependencies {
  363. if d.Type == "" {
  364. if depPom, ok := modules[d.BpName()]; ok {
  365. // We've seen the POM for this dependency, use its packaging
  366. // as the dependency type rather than Maven spec default.
  367. d.Type = depPom.Packaging
  368. } else {
  369. // Dependency type was not specified and we don't have the POM
  370. // for this artifact, use the default from Maven spec.
  371. d.Type = "jar"
  372. }
  373. }
  374. if d.Scope == "" {
  375. // Scope was not specified, use the default from Maven spec.
  376. d.Scope = "compile"
  377. }
  378. }
  379. }
  380. // ExtractMinSdkVersion extracts the minSdkVersion from the AndroidManifest.xml file inside an aar file, or sets it
  381. // to "current" if it is not present.
  382. func (p *Pom) ExtractMinSdkVersion() error {
  383. aar, err := zip.OpenReader(p.ArtifactFile)
  384. if err != nil {
  385. return err
  386. }
  387. defer aar.Close()
  388. var manifest *zip.File
  389. for _, f := range aar.File {
  390. if f.Name == "AndroidManifest.xml" {
  391. manifest = f
  392. break
  393. }
  394. }
  395. if manifest == nil {
  396. return fmt.Errorf("failed to find AndroidManifest.xml in %s", p.ArtifactFile)
  397. }
  398. r, err := manifest.Open()
  399. if err != nil {
  400. return err
  401. }
  402. defer r.Close()
  403. decoder := xml.NewDecoder(r)
  404. manifestData := struct {
  405. XMLName xml.Name `xml:"manifest"`
  406. Uses_sdk struct {
  407. MinSdkVersion string `xml:"http://schemas.android.com/apk/res/android minSdkVersion,attr"`
  408. } `xml:"uses-sdk"`
  409. }{}
  410. err = decoder.Decode(&manifestData)
  411. if err != nil {
  412. return err
  413. }
  414. p.MinSdkVersion = manifestData.Uses_sdk.MinSdkVersion
  415. if p.MinSdkVersion == "" {
  416. p.MinSdkVersion = "current"
  417. }
  418. return nil
  419. }
  420. var bpTemplate = template.Must(template.New("bp").Parse(`
  421. {{.ImportModuleType}} {
  422. name: "{{.BpName}}",
  423. {{- if .IsApk}}
  424. {{.ImportProperty}}: "{{.ArtifactFile}}",
  425. {{- else}}
  426. {{.ImportProperty}}: ["{{.ArtifactFile}}"],
  427. sdk_version: "{{.SdkVersion}}",
  428. {{- end}}
  429. {{- if .Jetifier}}
  430. jetifier: true,
  431. {{- end}}
  432. {{- if .IsHostAndDeviceModule}}
  433. host_supported: true,
  434. {{- end}}
  435. {{- if not .IsHostOnly}}
  436. apex_available: [
  437. "//apex_available:platform",
  438. "//apex_available:anyapex",
  439. ],
  440. {{- end}}
  441. {{- if .IsAar}}
  442. min_sdk_version: "{{.MinSdkVersion}}",
  443. static_libs: [
  444. {{- range .BpJarDeps}}
  445. "{{.}}",
  446. {{- end}}
  447. {{- range .BpAarDeps}}
  448. "{{.}}",
  449. {{- end}}
  450. {{- range .BpExtraStaticLibs}}
  451. "{{.}}",
  452. {{- end}}
  453. ],
  454. {{- if .BpExtraLibs}}
  455. libs: [
  456. {{- range .BpExtraLibs}}
  457. "{{.}}",
  458. {{- end}}
  459. ],
  460. {{- end}}
  461. {{- if .BpOptionalUsesLibs}}
  462. optional_uses_libs: [
  463. {{- range .BpOptionalUsesLibs}}
  464. "{{.}}",
  465. {{- end}}
  466. ],
  467. {{- end}}
  468. {{- else if not .IsHostOnly}}
  469. {{- if not .IsApk}}
  470. min_sdk_version: "{{.DefaultMinSdkVersion}}",
  471. {{- end}}
  472. {{- end}}
  473. {{- if .IsApk}}
  474. presigned: true
  475. {{- end}}
  476. }
  477. `))
  478. var bpDepsTemplate = template.Must(template.New("bp").Parse(`
  479. {{.ImportModuleType}} {
  480. name: "{{.BpName}}-nodeps",
  481. {{.ImportProperty}}: ["{{.ArtifactFile}}"],
  482. sdk_version: "{{.SdkVersion}}",
  483. {{- if .Jetifier}}
  484. jetifier: true,
  485. {{- end}}
  486. {{- if .IsHostAndDeviceModule}}
  487. host_supported: true,
  488. {{- end}}
  489. {{- if not .IsHostOnly}}
  490. apex_available: [
  491. "//apex_available:platform",
  492. "//apex_available:anyapex",
  493. ],
  494. {{- end}}
  495. {{- if .IsAar}}
  496. min_sdk_version: "{{.MinSdkVersion}}",
  497. static_libs: [
  498. {{- range .BpJarDeps}}
  499. "{{.}}",
  500. {{- end}}
  501. {{- range .BpAarDeps}}
  502. "{{.}}",
  503. {{- end}}
  504. {{- range .BpExtraStaticLibs}}
  505. "{{.}}",
  506. {{- end}}
  507. ],
  508. {{- if .BpExtraLibs}}
  509. libs: [
  510. {{- range .BpExtraLibs}}
  511. "{{.}}",
  512. {{- end}}
  513. ],
  514. {{- end}}
  515. {{- else if not .IsHostOnly}}
  516. min_sdk_version: "{{.DefaultMinSdkVersion}}",
  517. {{- end}}
  518. }
  519. {{.ModuleType}} {
  520. name: "{{.BpName}}",
  521. {{- if .IsDeviceModule}}
  522. sdk_version: "{{.SdkVersion}}",
  523. {{- if .IsHostAndDeviceModule}}
  524. host_supported: true,
  525. {{- end}}
  526. {{- if not .IsHostOnly}}
  527. apex_available: [
  528. "//apex_available:platform",
  529. "//apex_available:anyapex",
  530. ],
  531. {{- end}}
  532. {{- if .IsAar}}
  533. min_sdk_version: "{{.MinSdkVersion}}",
  534. manifest: "manifests/{{.BpName}}/AndroidManifest.xml",
  535. {{- else if not .IsHostOnly}}
  536. min_sdk_version: "{{.DefaultMinSdkVersion}}",
  537. {{- end}}
  538. {{- end}}
  539. static_libs: [
  540. "{{.BpName}}-nodeps",
  541. {{- range .BpJarDeps}}
  542. "{{.}}",
  543. {{- end}}
  544. {{- range .BpAarDeps}}
  545. "{{.}}",
  546. {{- end}}
  547. {{- range .BpExtraStaticLibs}}
  548. "{{.}}",
  549. {{- end}}
  550. ],
  551. {{- if .BpExtraLibs}}
  552. libs: [
  553. {{- range .BpExtraLibs}}
  554. "{{.}}",
  555. {{- end}}
  556. ],
  557. {{- end}}
  558. {{- if .BpOptionalUsesLibs}}
  559. optional_uses_libs: [
  560. {{- range .BpOptionalUsesLibs}}
  561. "{{.}}",
  562. {{- end}}
  563. ],
  564. {{- end}}
  565. java_version: "1.7",
  566. }
  567. `))
  568. var bazelTemplate = template.Must(template.New("bp").Parse(`
  569. {{.BazelImportTargetType}} (
  570. name = "{{.BpName}}",
  571. {{.BazelImportProperty}}: {{- if not .IsAar}}[{{- end}}"{{.ArtifactFile}}"{{- if not .IsAar}}]{{- end}},
  572. visibility = ["//visibility:public"],
  573. {{- if .IsAar}}
  574. deps = [
  575. {{- range .BazelJarDeps}}
  576. "{{.}}",
  577. {{- end}}
  578. {{- range .BazelAarDeps}}
  579. "{{.}}",
  580. {{- end}}
  581. {{- range .BpExtraStaticLibs}}
  582. "{{.}}",
  583. {{- end}}
  584. {{- range .BpExtraLibs}}
  585. "{{.}}",
  586. {{- end}}
  587. {{- range .BpOptionalUsesLibs}}
  588. "{{.}}",
  589. {{- end}}
  590. ],
  591. {{- end}}
  592. )
  593. `))
  594. var bazelDepsTemplate = template.Must(template.New("bp").Parse(`
  595. {{.BazelImportTargetType}} (
  596. name = "{{.BpName}}",
  597. {{.BazelImportProperty}} = {{- if not .IsAar}}[{{- end}}"{{.ArtifactFile}}"{{- if not .IsAar}}]{{- end}},
  598. visibility = ["//visibility:public"],
  599. exports = [
  600. {{- range .BazelJarDeps}}
  601. "{{.}}",
  602. {{- end}}
  603. {{- range .BazelAarDeps}}
  604. "{{.}}",
  605. {{- end}}
  606. {{- range .BpExtraStaticLibs}}
  607. "{{.}}",
  608. {{- end}}
  609. {{- range .BpExtraLibs}}
  610. "{{.}}",
  611. {{- end}}
  612. {{- range .BpOptionalUsesLibs}}
  613. "{{.}}",
  614. {{- end}}
  615. ],
  616. )
  617. `))
  618. func parse(filename string) (*Pom, error) {
  619. data, err := ioutil.ReadFile(filename)
  620. if err != nil {
  621. return nil, err
  622. }
  623. var pom Pom
  624. err = xml.Unmarshal(data, &pom)
  625. if err != nil {
  626. return nil, err
  627. }
  628. if useVersion != "" && pom.Version != useVersion {
  629. return nil, nil
  630. }
  631. if pom.Packaging == "" {
  632. pom.Packaging = "jar"
  633. }
  634. pom.PomFile = filename
  635. pom.ArtifactFile = strings.TrimSuffix(filename, ".pom") + "." + pom.Packaging
  636. return &pom, nil
  637. }
  638. func rerunForRegen(filename string) error {
  639. buf, err := ioutil.ReadFile(filename)
  640. if err != nil {
  641. return err
  642. }
  643. scanner := bufio.NewScanner(bytes.NewBuffer(buf))
  644. // Skip the first line in the file
  645. for i := 0; i < 2; i++ {
  646. if !scanner.Scan() {
  647. if scanner.Err() != nil {
  648. return scanner.Err()
  649. } else {
  650. return fmt.Errorf("unexpected EOF")
  651. }
  652. }
  653. }
  654. // Extract the old args from the file
  655. line := scanner.Text()
  656. if strings.HasPrefix(line, "// pom2bp ") { // .bp file
  657. line = strings.TrimPrefix(line, "// pom2bp ")
  658. } else if strings.HasPrefix(line, "// pom2mk ") { // .bp file converted from .mk file
  659. line = strings.TrimPrefix(line, "// pom2mk ")
  660. } else if strings.HasPrefix(line, "# pom2mk ") { // .mk file
  661. line = strings.TrimPrefix(line, "# pom2mk ")
  662. } else if strings.HasPrefix(line, "# pom2bp ") { // Bazel BUILD file
  663. line = strings.TrimPrefix(line, "# pom2bp ")
  664. } else {
  665. return fmt.Errorf("unexpected second line: %q", line)
  666. }
  667. args := strings.Split(line, " ")
  668. lastArg := args[len(args)-1]
  669. args = args[:len(args)-1]
  670. // Append all current command line args except -regen <file> to the ones from the file
  671. for i := 1; i < len(os.Args); i++ {
  672. if os.Args[i] == "-regen" || os.Args[i] == "--regen" {
  673. i++
  674. } else {
  675. args = append(args, os.Args[i])
  676. }
  677. }
  678. args = append(args, lastArg)
  679. cmd := os.Args[0] + " " + strings.Join(args, " ")
  680. // Re-exec pom2bp with the new arguments
  681. output, err := exec.Command("/bin/sh", "-c", cmd).Output()
  682. if exitErr, _ := err.(*exec.ExitError); exitErr != nil {
  683. return fmt.Errorf("failed to run %s\n%s", cmd, string(exitErr.Stderr))
  684. } else if err != nil {
  685. return err
  686. }
  687. // If the old file was a .mk file, replace it with a .bp file
  688. if filepath.Ext(filename) == ".mk" {
  689. os.Remove(filename)
  690. filename = strings.TrimSuffix(filename, ".mk") + ".bp"
  691. }
  692. return ioutil.WriteFile(filename, output, 0666)
  693. }
  694. func main() {
  695. flag.Usage = func() {
  696. fmt.Fprintf(os.Stderr, `pom2bp, a tool to create Android.bp files from maven repos
  697. The tool will extract the necessary information from *.pom files to create an Android.bp whose
  698. aar libraries can be linked against when using AAPT2.
  699. Usage: %s [--rewrite <regex>=<replace>] [--exclude <module>] [--extra-static-libs <module>=<module>[,<module>]] [--extra-libs <module>=<module>[,<module>]] [--optional-uses-libs <module>=<module>[,<module>]] [<dir>] [-regen <file>]
  700. -rewrite <regex>=<replace>
  701. rewrite can be used to specify mappings between Maven projects and Android.bp modules. The -rewrite
  702. option can be specified multiple times. When determining the Android.bp module for a given Maven
  703. project, mappings are searched in the order they were specified. The first <regex> matching
  704. either the Maven project's <groupId>:<artifactId> or <artifactId> will be used to generate
  705. the Android.bp module name using <replace>. If no matches are found, <artifactId> is used.
  706. -exclude <module>
  707. Don't put the specified module in the Android.bp file.
  708. -extra-static-libs <module>=<module>[,<module>]
  709. Some Android.bp modules have transitive static dependencies that must be specified when they
  710. are depended upon (like android-support-v7-mediarouter requires android-support-v7-appcompat).
  711. This may be specified multiple times to declare these dependencies.
  712. -extra-libs <module>=<module>[,<module>]
  713. Some Android.bp modules have transitive runtime dependencies that must be specified when they
  714. are depended upon (like androidx.test.rules requires android.test.base).
  715. This may be specified multiple times to declare these dependencies.
  716. -optional-uses-libs <module>=<module>[,<module>]
  717. Some Android.bp modules have optional dependencies (typically specified with <uses-library> in
  718. the module's AndroidManifest.xml) that must be specified when they are depended upon (like
  719. androidx.window:window optionally requires androidx.window:window-extensions).
  720. This may be specified multiple times to declare these dependencies.
  721. -sdk-version <version>
  722. Sets sdk_version: "<version>" for all modules.
  723. -default-min-sdk-version
  724. The default min_sdk_version to use for a module if one cannot be mined from AndroidManifest.xml
  725. -use-version <version>
  726. If the maven directory contains multiple versions of artifacts and their pom files,
  727. -use-version can be used to only write Android.bp files for a specific version of those artifacts.
  728. -write-cmd
  729. Whether to write the command line arguments used to generate the build file as a comment at
  730. the top of the build file itself.
  731. -jetifier
  732. Sets jetifier: true for all modules.
  733. <dir>
  734. The directory to search for *.pom files under.
  735. The contents are written to stdout, to be put in the current directory (often as Android.bp)
  736. -regen <file>
  737. Read arguments from <file> and overwrite it (if it ends with .bp) or move it to .bp (if it
  738. ends with .mk).
  739. `, os.Args[0])
  740. }
  741. var regen string
  742. var pom2build bool
  743. var prepend string
  744. flag.Var(&excludes, "exclude", "Exclude module")
  745. flag.Var(&extraStaticLibs, "extra-static-libs", "Extra static dependencies needed when depending on a module")
  746. flag.Var(&extraLibs, "extra-libs", "Extra runtime dependencies needed when depending on a module")
  747. flag.Var(&optionalUsesLibs, "optional-uses-libs", "Extra optional dependencies needed when depending on a module")
  748. flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
  749. flag.Var(&hostModuleNames, "host", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is a host module")
  750. flag.Var(&hostAndDeviceModuleNames, "host-and-device", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is both a host and device module.")
  751. flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
  752. flag.StringVar(&defaultMinSdkVersion, "default-min-sdk-version", "24", "Default min_sdk_version to use, if one is not available from AndroidManifest.xml. Default: 24")
  753. flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
  754. flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
  755. flag.BoolVar(&writeCmd, "write-cmd", true, "Write command line arguments as a comment")
  756. flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
  757. flag.StringVar(&regen, "regen", "", "Rewrite specified file")
  758. flag.BoolVar(&pom2build, "pom2build", false, "If true, will generate a Bazel BUILD file *instead* of a .bp file")
  759. flag.StringVar(&prepend, "prepend", "", "Path to a file containing text to insert at the beginning of the generated build file")
  760. flag.Parse()
  761. if regen != "" {
  762. err := rerunForRegen(regen)
  763. if err != nil {
  764. fmt.Fprintln(os.Stderr, err)
  765. os.Exit(1)
  766. }
  767. os.Exit(0)
  768. }
  769. if flag.NArg() == 0 {
  770. fmt.Fprintln(os.Stderr, "Directory argument is required")
  771. os.Exit(1)
  772. } else if flag.NArg() > 1 {
  773. fmt.Fprintln(os.Stderr, "Multiple directories provided:", strings.Join(flag.Args(), " "))
  774. os.Exit(1)
  775. }
  776. dir := flag.Arg(0)
  777. absDir, err := filepath.Abs(dir)
  778. if err != nil {
  779. fmt.Fprintln(os.Stderr, "Failed to get absolute directory:", err)
  780. os.Exit(1)
  781. }
  782. var filenames []string
  783. err = filepath.Walk(absDir, func(path string, info os.FileInfo, err error) error {
  784. if err != nil {
  785. return err
  786. }
  787. name := info.Name()
  788. if info.IsDir() {
  789. if strings.HasPrefix(name, ".") {
  790. return filepath.SkipDir
  791. }
  792. return nil
  793. }
  794. if strings.HasPrefix(name, ".") {
  795. return nil
  796. }
  797. if strings.HasSuffix(name, ".pom") {
  798. path, err = filepath.Rel(absDir, path)
  799. if err != nil {
  800. return err
  801. }
  802. filenames = append(filenames, filepath.Join(dir, path))
  803. }
  804. return nil
  805. })
  806. if err != nil {
  807. fmt.Fprintln(os.Stderr, "Error walking files:", err)
  808. os.Exit(1)
  809. }
  810. if len(filenames) == 0 {
  811. fmt.Fprintln(os.Stderr, "Error: no *.pom files found under", dir)
  812. os.Exit(1)
  813. }
  814. sort.Strings(filenames)
  815. poms := []*Pom{}
  816. modules := make(map[string]*Pom)
  817. duplicate := false
  818. for _, filename := range filenames {
  819. pom, err := parse(filename)
  820. if err != nil {
  821. fmt.Fprintln(os.Stderr, "Error converting", filename, err)
  822. os.Exit(1)
  823. }
  824. if pom != nil {
  825. key := pom.BpName()
  826. if excludes[key] {
  827. continue
  828. }
  829. if old, ok := modules[key]; ok {
  830. fmt.Fprintln(os.Stderr, "Module", key, "defined twice:", old.PomFile, pom.PomFile)
  831. duplicate = true
  832. }
  833. poms = append(poms, pom)
  834. modules[key] = pom
  835. }
  836. }
  837. if duplicate {
  838. os.Exit(1)
  839. }
  840. if pom2build {
  841. if err := InitRefreshMod(poms); err != nil {
  842. fmt.Fprintf(os.Stderr, "Error in refreshmod: %s", err)
  843. os.Exit(1)
  844. }
  845. BazelifyExtraDeps(extraStaticLibs, modules)
  846. BazelifyExtraDeps(extraLibs, modules)
  847. BazelifyExtraDeps(optionalUsesLibs, modules)
  848. }
  849. for _, pom := range poms {
  850. if pom.IsAar() {
  851. err := pom.ExtractMinSdkVersion()
  852. if err != nil {
  853. fmt.Fprintf(os.Stderr, "Error reading manifest for %s: %s", pom.ArtifactFile, err)
  854. os.Exit(1)
  855. }
  856. }
  857. pom.FixDeps(modules)
  858. if pom2build {
  859. pom.GetBazelDepNames(modules)
  860. }
  861. }
  862. buf := &bytes.Buffer{}
  863. commentString := "//"
  864. if pom2build {
  865. commentString = "#"
  866. }
  867. fmt.Fprintln(buf, commentString, "This is a generated file. Do not modify directly.")
  868. if writeCmd {
  869. fmt.Fprintln(buf, commentString, "Automatically generated with:")
  870. fmt.Fprintln(buf, commentString, "pom2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
  871. }
  872. if prepend != "" {
  873. contents, err := ioutil.ReadFile(prepend)
  874. if err != nil {
  875. fmt.Fprintln(os.Stderr, "Error reading", prepend, err)
  876. os.Exit(1)
  877. }
  878. fmt.Fprintln(buf, string(contents))
  879. }
  880. depsTemplate := bpDepsTemplate
  881. template := bpTemplate
  882. if pom2build {
  883. depsTemplate = bazelDepsTemplate
  884. template = bazelTemplate
  885. }
  886. for _, pom := range poms {
  887. var err error
  888. if staticDeps && !pom.IsApk() {
  889. err = depsTemplate.Execute(buf, pom)
  890. } else {
  891. err = template.Execute(buf, pom)
  892. }
  893. if err != nil {
  894. fmt.Fprintln(os.Stderr, "Error writing", pom.PomFile, pom.BpName(), err)
  895. os.Exit(1)
  896. }
  897. }
  898. if pom2build {
  899. os.Stdout.WriteString(buf.String())
  900. } else {
  901. out, err := bpfix.Reformat(buf.String())
  902. if err != nil {
  903. fmt.Fprintln(os.Stderr, "Error formatting output", err)
  904. os.Exit(1)
  905. }
  906. os.Stdout.WriteString(out)
  907. }
  908. }