1// Copyright 2018 The Bazel Authors. 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 link is a thin wrapper around aapt2 to link android resources. 16package link 17 18import ( 19 "flag" 20 "io/ioutil" 21 "log" 22 "os/exec" 23 "sync" 24 25 "src/common/golang/flags" 26 "src/common/golang/walk" 27 "src/common/golang/ziputils" 28 "src/tools/ak/types" 29) 30 31var ( 32 // Cmd defines the command to run link. 33 Cmd = types.Command{ 34 Init: Init, 35 Run: Run, 36 Desc: desc, 37 Flags: []string{ 38 "aapt2", 39 "sdk_jar", 40 "manifest", 41 "res_dirs", 42 "asset_dirs", 43 "pkg", 44 "src_jar", 45 "out", 46 }, 47 } 48 49 aapt2 string 50 sdkJar string 51 manifest string 52 resDirs flags.StringList 53 assetDirs flags.StringList 54 pkg string 55 srcJar string 56 out string 57 58 initOnce sync.Once 59) 60 61// Init initializes link. 62func Init() { 63 initOnce.Do(func() { 64 flag.StringVar(&aapt2, "aapt2", "", "Path to the aapt2 binary.") 65 flag.StringVar(&sdkJar, "sdk_jar", "", "Path to the android jar.") 66 flag.StringVar(&manifest, "manifest", "", "Path to the application AndroidManifest.xml.") 67 flag.Var(&resDirs, "res_dirs", "List of resource archives to link.") 68 flag.Var(&assetDirs, "asset_dirs", "Paths to asset directories..") 69 flag.StringVar(&pkg, "pkg", "", "Package for R.java.") 70 flag.StringVar(&srcJar, "src_jar", "", "R java source jar path.") 71 flag.StringVar(&out, "out", "", "Output path for linked archive.") 72 }) 73} 74 75func desc() string { 76 return "Link compiled Android resources." 77} 78 79// Run is the entry point for link. 80func Run() { 81 if aapt2 == "" || 82 sdkJar == "" || 83 manifest == "" || 84 resDirs == nil || 85 pkg == "" || 86 srcJar == "" || 87 out == "" { 88 log.Fatal("Flags -aapt2 -sdk_jar -manifest -res_dirs -pkg -src_jar and -out must be specified.") 89 } 90 91 // Note that relative order between directories needs to be respected by traversal function. 92 // I.e. all files in dir n most come before all files in directory n+1. 93 resArchives, err := walk.Files(resDirs) 94 if err != nil { 95 log.Fatalf("error getting resource archives: %v", err) 96 } 97 98 rjavaDir, err := ioutil.TempDir("", "rjava") 99 if err != nil { 100 log.Fatalf("error creating temp dir: %v", err) 101 } 102 103 args := []string{ 104 "link", "--manifest", manifest, "--auto-add-overlay", "--no-static-lib-packages", 105 "--java", rjavaDir, "--custom-package", pkg, "-I", sdkJar} 106 107 for _, r := range resArchives { 108 args = append(args, "-R", r) 109 } 110 111 for _, a := range assetDirs { 112 args = append(args, "-A", a) 113 } 114 115 args = append(args, "-o", out) 116 117 if out, err := exec.Command(aapt2, args...).CombinedOutput(); err != nil { 118 log.Fatalf("error linking Android resources: %v\n %s", err, string(out)) 119 } 120 if err := ziputils.Zip(rjavaDir, srcJar); err != nil { 121 log.Fatalf("error unable to create resources src jar: %v", err) 122 } 123} 124