Merge "Add sdkextensions tests to soong TEST_MAPPING"
diff --git a/apex/apex.go b/apex/apex.go
index 3448327..926085b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2020,7 +2020,7 @@
a.filesInfo = filesInfo
// Set suffix and primaryApexType depending on the ApexType
- buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuildApps()
+ buildFlattenedAsDefault := ctx.Config().FlattenApex()
switch a.properties.ApexType {
case imageApex:
if buildFlattenedAsDefault {
diff --git a/cmd/go2bp/Android.bp b/cmd/go2bp/Android.bp
new file mode 100644
index 0000000..53d70b6
--- /dev/null
+++ b/cmd/go2bp/Android.bp
@@ -0,0 +1,26 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "go2bp",
+ deps: [
+ "blueprint-proptools",
+ "bpfix-lib",
+ ],
+ srcs: ["go2bp.go"],
+}
diff --git a/cmd/go2bp/go2bp.go b/cmd/go2bp/go2bp.go
new file mode 100644
index 0000000..67138f1
--- /dev/null
+++ b/cmd/go2bp/go2bp.go
@@ -0,0 +1,361 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sort"
+ "strings"
+ "text/template"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/bpfix/bpfix"
+)
+
+type RewriteNames []RewriteName
+type RewriteName struct {
+ prefix string
+ repl string
+}
+
+func (r *RewriteNames) String() string {
+ return ""
+}
+
+func (r *RewriteNames) Set(v string) error {
+ split := strings.SplitN(v, "=", 2)
+ if len(split) != 2 {
+ return fmt.Errorf("Must be in the form of <prefix>=<replace>")
+ }
+ *r = append(*r, RewriteName{
+ prefix: split[0],
+ repl: split[1],
+ })
+ return nil
+}
+
+func (r *RewriteNames) GoToBp(name string) string {
+ ret := name
+ for _, r := range *r {
+ prefix := r.prefix
+ if name == prefix {
+ ret = r.repl
+ break
+ }
+ prefix += "/"
+ if strings.HasPrefix(name, prefix) {
+ ret = r.repl + "-" + strings.TrimPrefix(name, prefix)
+ }
+ }
+ return strings.ReplaceAll(ret, "/", "-")
+}
+
+var rewriteNames = RewriteNames{}
+
+type Exclude map[string]bool
+
+func (e Exclude) String() string {
+ return ""
+}
+
+func (e Exclude) Set(v string) error {
+ e[v] = true
+ return nil
+}
+
+var excludes = make(Exclude)
+var excludeDeps = make(Exclude)
+var excludeSrcs = make(Exclude)
+
+type GoModule struct {
+ Dir string
+}
+
+type GoPackage struct {
+ Dir string
+ ImportPath string
+ Name string
+ Imports []string
+ GoFiles []string
+ TestGoFiles []string
+ TestImports []string
+
+ Module *GoModule
+}
+
+func (g GoPackage) IsCommand() bool {
+ return g.Name == "main"
+}
+
+func (g GoPackage) BpModuleType() string {
+ if g.IsCommand() {
+ return "blueprint_go_binary"
+ }
+ return "bootstrap_go_package"
+}
+
+func (g GoPackage) BpName() string {
+ if g.IsCommand() {
+ return filepath.Base(g.ImportPath)
+ }
+ return rewriteNames.GoToBp(g.ImportPath)
+}
+
+func (g GoPackage) BpDeps(deps []string) []string {
+ var ret []string
+ for _, d := range deps {
+ // Ignore stdlib dependencies
+ if !strings.Contains(d, ".") {
+ continue
+ }
+ if _, ok := excludeDeps[d]; ok {
+ continue
+ }
+ name := rewriteNames.GoToBp(d)
+ ret = append(ret, name)
+ }
+ return ret
+}
+
+func (g GoPackage) BpSrcs(srcs []string) []string {
+ var ret []string
+ prefix, err := filepath.Rel(g.Module.Dir, g.Dir)
+ if err != nil {
+ panic(err)
+ }
+ for _, f := range srcs {
+ f = filepath.Join(prefix, f)
+ if _, ok := excludeSrcs[f]; ok {
+ continue
+ }
+ ret = append(ret, f)
+ }
+ return ret
+}
+
+// AllImports combines Imports and TestImports, as blueprint does not differentiate these.
+func (g GoPackage) AllImports() []string {
+ imports := append([]string(nil), g.Imports...)
+ imports = append(imports, g.TestImports...)
+
+ if len(imports) == 0 {
+ return nil
+ }
+
+ // Sort and de-duplicate
+ sort.Strings(imports)
+ j := 0
+ for i := 1; i < len(imports); i++ {
+ if imports[i] == imports[j] {
+ continue
+ }
+ j++
+ imports[j] = imports[i]
+ }
+ return imports[:j+1]
+}
+
+var bpTemplate = template.Must(template.New("bp").Parse(`
+{{.BpModuleType}} {
+ name: "{{.BpName}}",
+ {{- if not .IsCommand}}
+ pkgPath: "{{.ImportPath}}",
+ {{- end}}
+ {{- if .BpDeps .AllImports}}
+ deps: [
+ {{- range .BpDeps .AllImports}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
+ {{- if .BpSrcs .GoFiles}}
+ srcs: [
+ {{- range .BpSrcs .GoFiles}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
+ {{- if .BpSrcs .TestGoFiles}}
+ testSrcs: [
+ {{- range .BpSrcs .TestGoFiles}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
+}
+`))
+
+func rerunForRegen(filename string) error {
+ buf, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+
+ scanner := bufio.NewScanner(bytes.NewBuffer(buf))
+
+ // Skip the first line in the file
+ for i := 0; i < 2; i++ {
+ if !scanner.Scan() {
+ if scanner.Err() != nil {
+ return scanner.Err()
+ } else {
+ return fmt.Errorf("unexpected EOF")
+ }
+ }
+ }
+
+ // Extract the old args from the file
+ line := scanner.Text()
+ if strings.HasPrefix(line, "// go2bp ") {
+ line = strings.TrimPrefix(line, "// go2bp ")
+ } else {
+ return fmt.Errorf("unexpected second line: %q", line)
+ }
+ args := strings.Split(line, " ")
+ lastArg := args[len(args)-1]
+ args = args[:len(args)-1]
+
+ // Append all current command line args except -regen <file> to the ones from the file
+ for i := 1; i < len(os.Args); i++ {
+ if os.Args[i] == "-regen" || os.Args[i] == "--regen" {
+ i++
+ } else {
+ args = append(args, os.Args[i])
+ }
+ }
+ args = append(args, lastArg)
+
+ cmd := os.Args[0] + " " + strings.Join(args, " ")
+ // Re-exec pom2bp with the new arguments
+ output, err := exec.Command("/bin/sh", "-c", cmd).Output()
+ if exitErr, _ := err.(*exec.ExitError); exitErr != nil {
+ return fmt.Errorf("failed to run %s\n%s", cmd, string(exitErr.Stderr))
+ } else if err != nil {
+ return err
+ }
+
+ return ioutil.WriteFile(filename, output, 0666)
+}
+
+func main() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, `go2bp, a tool to create Android.bp files from go modules
+
+The tool will extract the necessary information from Go files to create an Android.bp that can
+compile them. This needs to be run from the same directory as the go.mod file.
+
+Usage: %s [--rewrite <pkg-prefix>=<replace>] [-exclude <package>] [-regen <file>]
+
+ -rewrite <pkg-prefix>=<replace>
+ rewrite can be used to specify mappings between go package paths and Android.bp modules. The -rewrite
+ option can be specified multiple times. When determining the Android.bp module for a given Go
+ package, mappings are searched in the order they were specified. The first <pkg-prefix> matching
+ either the package directly, or as the prefix '<pkg-prefix>/' will be replaced with <replace>.
+ After all replacements are finished, all '/' characters are replaced with '-'.
+ -exclude <package>
+ Don't put the specified go package in the Android.bp file.
+ -exclude-deps <package>
+ Don't put the specified go package in the dependency lists.
+ -exclude-srcs <module>
+ Don't put the specified source files in srcs or testSrcs lists.
+ -regen <file>
+ Read arguments from <file> and overwrite it.
+
+`, os.Args[0])
+ }
+
+ var regen string
+
+ flag.Var(&excludes, "exclude", "Exclude go package")
+ flag.Var(&excludeDeps, "exclude-dep", "Exclude go package from deps")
+ flag.Var(&excludeSrcs, "exclude-src", "Exclude go file from source lists")
+ flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
+ flag.StringVar(®en, "regen", "", "Rewrite specified file")
+ flag.Parse()
+
+ if regen != "" {
+ err := rerunForRegen(regen)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ os.Exit(0)
+ }
+
+ if flag.NArg() != 0 {
+ fmt.Fprintf(os.Stderr, "Unused argument detected: %v\n", flag.Args())
+ os.Exit(1)
+ }
+
+ if _, err := os.Stat("go.mod"); err != nil {
+ fmt.Fprintln(os.Stderr, "go.mod file not found")
+ os.Exit(1)
+ }
+
+ cmd := exec.Command("go", "list", "-json", "./...")
+ output, err := cmd.Output()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to dump the go packages: %v\n", err)
+ os.Exit(1)
+ }
+ decoder := json.NewDecoder(bytes.NewReader(output))
+
+ pkgs := []GoPackage{}
+ for decoder.More() {
+ pkg := GoPackage{}
+ err := decoder.Decode(&pkg)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to parse json: %v\n", err)
+ os.Exit(1)
+ }
+ pkgs = append(pkgs, pkg)
+ }
+
+ buf := &bytes.Buffer{}
+
+ fmt.Fprintln(buf, "// Automatically generated with:")
+ fmt.Fprintln(buf, "// go2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
+
+ for _, pkg := range pkgs {
+ if excludes[pkg.ImportPath] {
+ continue
+ }
+ if len(pkg.BpSrcs(pkg.GoFiles)) == 0 && len(pkg.BpSrcs(pkg.TestGoFiles)) == 0 {
+ continue
+ }
+ err := bpTemplate.Execute(buf, pkg)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "Error writing", pkg.Name, err)
+ os.Exit(1)
+ }
+ }
+
+ out, err := bpfix.Reformat(buf.String())
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "Error formatting output", err)
+ os.Exit(1)
+ }
+
+ os.Stdout.WriteString(out)
+}
diff --git a/java/base.go b/java/base.go
index f7989b8..440b004 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1778,3 +1778,9 @@
func (j *Module) ProvidesUsesLib() *string {
return j.usesLibraryProperties.Provides_uses_lib
}
+
+type ModuleWithStem interface {
+ Stem() string
+}
+
+var _ ModuleWithStem = (*Module)(nil)
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 188d362..44803a9 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -496,10 +496,21 @@
global := dexpreopt.GetGlobalConfig(ctx)
+ // Convert content names to their appropriate stems, in case a test library is overriding an actual boot jar
+ var stems []string
+ for _, name := range b.properties.Contents {
+ dep := ctx.GetDirectDepWithTag(name, bootclasspathFragmentContentDepTag)
+ if m, ok := dep.(ModuleWithStem); ok {
+ stems = append(stems, m.Stem())
+ } else {
+ ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
+ }
+ }
+
// Only create configs for updatable boot jars. Non-updatable boot jars must be part of the
// platform_bootclasspath's classpath proto config to guarantee that they come before any
// updatable jars at runtime.
- return global.UpdatableBootJars.Filter(b.properties.Contents)
+ return global.UpdatableBootJars.Filter(stems)
}
func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 9111c30..f973cf4 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -97,10 +97,21 @@
func (s *SystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
global := dexpreopt.GetGlobalConfig(ctx)
+ // Convert content names to their appropriate stems, in case a test library is overriding an actual boot jar
+ var stems []string
+ for _, name := range s.properties.Contents {
+ dep := ctx.GetDirectDepWithTag(name, systemServerClasspathFragmentContentDepTag)
+ if m, ok := dep.(ModuleWithStem); ok {
+ stems = append(stems, m.Stem())
+ } else {
+ ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
+ }
+ }
+
// Only create configs for updatable boot jars. Non-updatable system server jars must be part of the
// platform_systemserverclasspath's classpath proto config to guarantee that they come before any
// updatable jars at runtime.
- return global.UpdatableSystemServerJars.Filter(s.properties.Contents)
+ return global.UpdatableSystemServerJars.Filter(stems)
}
type systemServerClasspathFragmentContentDependencyTag struct {