java_sdk_library: Access outputs using tags
Previously, in order to access say the public stubs source jar it was necessary to directly reference the module by name. This change adds support for accessing them indirectly via tags. Test: nothing Bug: 155164730 Change-Id: Id6d76e56c7b46944b2d2a44a2163fb05a5b03de9
This commit is contained in:
parent
0f8faffdc0
commit
46dc45aba9
|
@ -1230,6 +1230,113 @@ func TestJavaSdkLibrary(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
|
||||||
|
testJava(t, `
|
||||||
|
java_sdk_library {
|
||||||
|
name: "foo",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
api_packages: ["foo"],
|
||||||
|
public: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "bar",
|
||||||
|
srcs: ["b.java", ":foo{.public.stubs.source}"],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
|
||||||
|
testJavaError(t, `"foo" does not provide api scope system`, `
|
||||||
|
java_sdk_library {
|
||||||
|
name: "foo",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
api_packages: ["foo"],
|
||||||
|
public: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "bar",
|
||||||
|
srcs: ["b.java", ":foo{.system.stubs.source}"],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
|
||||||
|
testJava(t, `
|
||||||
|
java_sdk_library_import {
|
||||||
|
name: "foo",
|
||||||
|
public: {
|
||||||
|
jars: ["a.jar"],
|
||||||
|
stub_srcs: ["a.java"],
|
||||||
|
current_api: "api/current.txt",
|
||||||
|
removed_api: "api/removed.txt",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "bar",
|
||||||
|
srcs: [":foo{.public.stubs.source}"],
|
||||||
|
java_resources: [
|
||||||
|
":foo{.public.api.txt}",
|
||||||
|
":foo{.public.removed-api.txt}",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
java_sdk_library_import {
|
||||||
|
name: "foo",
|
||||||
|
public: {
|
||||||
|
jars: ["a.jar"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
t.Run("stubs.source", func(t *testing.T) {
|
||||||
|
testJavaError(t, `stubs.source not available for api scope public`, bp+`
|
||||||
|
java_library {
|
||||||
|
name: "bar",
|
||||||
|
srcs: [":foo{.public.stubs.source}"],
|
||||||
|
java_resources: [
|
||||||
|
":foo{.public.api.txt}",
|
||||||
|
":foo{.public.removed-api.txt}",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("api.txt", func(t *testing.T) {
|
||||||
|
testJavaError(t, `api.txt not available for api scope public`, bp+`
|
||||||
|
java_library {
|
||||||
|
name: "bar",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
java_resources: [
|
||||||
|
":foo{.public.api.txt}",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("removed-api.txt", func(t *testing.T) {
|
||||||
|
testJavaError(t, `removed-api.txt not available for api scope public`, bp+`
|
||||||
|
java_library {
|
||||||
|
name: "bar",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
java_resources: [
|
||||||
|
":foo{.public.removed-api.txt}",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
|
func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
|
||||||
testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, `
|
testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, `
|
||||||
java_sdk_library {
|
java_sdk_library {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -145,6 +146,8 @@ type apiScope struct {
|
||||||
// Initialize a scope, creating and adding appropriate dependency tags
|
// Initialize a scope, creating and adding appropriate dependency tags
|
||||||
func initApiScope(scope *apiScope) *apiScope {
|
func initApiScope(scope *apiScope) *apiScope {
|
||||||
name := scope.name
|
name := scope.name
|
||||||
|
scopeByName[name] = scope
|
||||||
|
allScopeNames = append(allScopeNames, name)
|
||||||
scope.propertyName = strings.ReplaceAll(name, "-", "_")
|
scope.propertyName = strings.ReplaceAll(name, "-", "_")
|
||||||
scope.fieldName = proptools.FieldNameForProperty(scope.propertyName)
|
scope.fieldName = proptools.FieldNameForProperty(scope.propertyName)
|
||||||
scope.stubsTag = scopeDependencyTag{
|
scope.stubsTag = scopeDependencyTag{
|
||||||
|
@ -217,6 +220,8 @@ func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
scopeByName = make(map[string]*apiScope)
|
||||||
|
allScopeNames []string
|
||||||
apiScopePublic = initApiScope(&apiScope{
|
apiScopePublic = initApiScope(&apiScope{
|
||||||
name: "public",
|
name: "public",
|
||||||
|
|
||||||
|
@ -578,6 +583,82 @@ func (c *commonToSdkLibraryAndImport) apiModuleName(apiScope *apiScope) string {
|
||||||
return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName())
|
return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The component names for different outputs of the java_sdk_library.
|
||||||
|
//
|
||||||
|
// They are similar to the names used for the child modules it creates
|
||||||
|
const (
|
||||||
|
stubsSourceComponentName = "stubs.source"
|
||||||
|
|
||||||
|
apiTxtComponentName = "api.txt"
|
||||||
|
|
||||||
|
removedApiTxtComponentName = "removed-api.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A regular expression to match tags that reference a specific stubs component.
|
||||||
|
//
|
||||||
|
// It will only match if given a valid scope and a valid component. It is verfy strict
|
||||||
|
// to ensure it does not accidentally match a similar looking tag that should be processed
|
||||||
|
// by the embedded Library.
|
||||||
|
var tagSplitter = func() *regexp.Regexp {
|
||||||
|
// Given a list of literal string items returns a regular expression that will
|
||||||
|
// match any one of the items.
|
||||||
|
choice := func(items ...string) string {
|
||||||
|
return `\Q` + strings.Join(items, `\E|\Q`) + `\E`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular expression to match one of the scopes.
|
||||||
|
scopesRegexp := choice(allScopeNames...)
|
||||||
|
|
||||||
|
// Regular expression to match one of the components.
|
||||||
|
componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName)
|
||||||
|
|
||||||
|
// Regular expression to match any combination of one scope and one component.
|
||||||
|
return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp))
|
||||||
|
}()
|
||||||
|
|
||||||
|
// For OutputFileProducer interface
|
||||||
|
//
|
||||||
|
// .<scope>.stubs.source
|
||||||
|
// .<scope>.api.txt
|
||||||
|
// .<scope>.removed-api.txt
|
||||||
|
func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) {
|
||||||
|
if groups := tagSplitter.FindStringSubmatch(tag); groups != nil {
|
||||||
|
scopeName := groups[1]
|
||||||
|
component := groups[2]
|
||||||
|
|
||||||
|
if scope, ok := scopeByName[scopeName]; ok {
|
||||||
|
paths := c.findScopePaths(scope)
|
||||||
|
if paths == nil {
|
||||||
|
return nil, fmt.Errorf("%q does not provide api scope %s", c.moduleBase.BaseModuleName(), scopeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch component {
|
||||||
|
case stubsSourceComponentName:
|
||||||
|
if paths.stubsSrcJar.Valid() {
|
||||||
|
return android.Paths{paths.stubsSrcJar.Path()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
case apiTxtComponentName:
|
||||||
|
if paths.currentApiFilePath.Valid() {
|
||||||
|
return android.Paths{paths.currentApiFilePath.Path()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
case removedApiTxtComponentName:
|
||||||
|
if paths.removedApiFilePath.Valid() {
|
||||||
|
return android.Paths{paths.removedApiFilePath.Path()}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unknown scope %s in %s", scope, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths {
|
func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths {
|
||||||
if c.scopePaths == nil {
|
if c.scopePaths == nil {
|
||||||
c.scopePaths = make(map[*apiScope]*scopePaths)
|
c.scopePaths = make(map[*apiScope]*scopePaths)
|
||||||
|
@ -751,6 +832,15 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
|
||||||
module.Library.deps(ctx)
|
module.Library.deps(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
|
||||||
|
paths, err := module.commonOutputFiles(tag)
|
||||||
|
if paths == nil && err == nil {
|
||||||
|
return module.Library.OutputFiles(tag)
|
||||||
|
} else {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
// Don't build an implementation library if this is api only.
|
// Don't build an implementation library if this is api only.
|
||||||
if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
|
if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
|
||||||
|
@ -1516,6 +1606,10 @@ func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (module *sdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
|
||||||
|
return module.commonOutputFiles(tag)
|
||||||
|
}
|
||||||
|
|
||||||
func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
// Record the paths to the prebuilt stubs library and stubs source.
|
// Record the paths to the prebuilt stubs library and stubs source.
|
||||||
ctx.VisitDirectDeps(func(to android.Module) {
|
ctx.VisitDirectDeps(func(to android.Module) {
|
||||||
|
|
Loading…
Reference in New Issue