For each sdk built generate a JSON file describing its contents
Some build scripts need to know information about the contents of an sdk, such as what APIs it provides (via java_sdk_library). Rather than duplicate that information in the scripts or attempt to access that information (where available) by looking at the contents of the snapshot this change generates a JSON file that sits alongside the snapshot itself. The info file can be generated without generating the snapshot zip file but whenever a snapshot zip file is generated the info is generated too. The info file sits alongside the zip file in out/mainline-sdks. Bug: 204763318 Test: m art-module-sdk m dist Change-Id: I289530bb21693dc6443826c24c17c9b5d85d2d8b
This commit is contained in:
@@ -795,6 +795,44 @@ sdk_snapshot {
|
||||
.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
|
||||
.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
|
||||
.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
|
||||
`),
|
||||
checkInfoContents(`
|
||||
[
|
||||
{
|
||||
"@type": "sdk",
|
||||
"@name": "mysdk",
|
||||
"java_header_libs": [
|
||||
"exported-system-module",
|
||||
"system-module"
|
||||
],
|
||||
"java_sdk_libs": [
|
||||
"myjavalib"
|
||||
],
|
||||
"java_system_modules": [
|
||||
"my-system-modules"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "java_library",
|
||||
"@name": "exported-system-module"
|
||||
},
|
||||
{
|
||||
"@type": "java_system_modules",
|
||||
"@name": "my-system-modules",
|
||||
"@deps": [
|
||||
"exported-system-module",
|
||||
"system-module"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "java_sdk_library",
|
||||
"@name": "myjavalib"
|
||||
},
|
||||
{
|
||||
"@type": "java_library",
|
||||
"@name": "system-module"
|
||||
}
|
||||
]
|
||||
`),
|
||||
)
|
||||
}
|
||||
|
17
sdk/sdk.go
17
sdk/sdk.go
@@ -75,6 +75,8 @@ type sdk struct {
|
||||
|
||||
snapshotFile android.OptionalPath
|
||||
|
||||
infoFile android.OptionalPath
|
||||
|
||||
// The builder, preserved for testing.
|
||||
builderForTests *snapshotBuilder
|
||||
}
|
||||
@@ -191,27 +193,32 @@ func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
}
|
||||
|
||||
// Generate the snapshot from the member info.
|
||||
p := s.buildSnapshot(ctx, sdkVariants)
|
||||
zip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), p.Base(), p)
|
||||
s.snapshotFile = android.OptionalPathForPath(zip)
|
||||
s.buildSnapshot(ctx, sdkVariants)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries {
|
||||
if !s.snapshotFile.Valid() {
|
||||
if !s.snapshotFile.Valid() != !s.infoFile.Valid() {
|
||||
panic("Snapshot (%q) and info file (%q) should both be set or neither should be set.")
|
||||
} else if !s.snapshotFile.Valid() {
|
||||
return []android.AndroidMkEntries{}
|
||||
}
|
||||
|
||||
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
||||
Class: "FAKE",
|
||||
OutputFile: s.snapshotFile,
|
||||
DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()),
|
||||
DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path(), s.infoFile.Path()),
|
||||
Include: "$(BUILD_PHONY_PACKAGE)",
|
||||
ExtraFooters: []android.AndroidMkExtraFootersFunc{
|
||||
func(w io.Writer, name, prefix, moduleDir string) {
|
||||
// Allow the sdk to be built by simply passing its name on the command line.
|
||||
fmt.Fprintln(w, ".PHONY:", s.Name())
|
||||
fmt.Fprintln(w, s.Name()+":", s.snapshotFile.String())
|
||||
|
||||
// Allow the sdk info to be built by simply passing its name on the command line.
|
||||
infoTarget := s.Name() + ".info"
|
||||
fmt.Fprintln(w, ".PHONY:", infoTarget)
|
||||
fmt.Fprintln(w, infoTarget+":", s.infoFile.String())
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
@@ -263,7 +263,10 @@ func TestSdkInstall(t *testing.T) {
|
||||
result := testSdkWithFs(t, sdk, nil)
|
||||
|
||||
CheckSnapshot(t, result, "mysdk", "",
|
||||
checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`))
|
||||
checkAllOtherCopyRules(`
|
||||
.intermediates/mysdk/common_os/mysdk-current.info -> mysdk-current.info
|
||||
.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip
|
||||
`))
|
||||
}
|
||||
|
||||
type EmbeddedPropertiesStruct struct {
|
||||
|
@@ -142,6 +142,7 @@ func getSdkSnapshotBuildInfo(t *testing.T, result *android.TestResult, sdk *sdk)
|
||||
androidBpContents: sdk.GetAndroidBpContentsForTests(),
|
||||
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
|
||||
androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(),
|
||||
infoContents: sdk.GetInfoContentsForTests(),
|
||||
snapshotTestCustomizations: map[snapshotTest]*snapshotTestCustomization{},
|
||||
targetBuildRelease: sdk.builderForTests.targetBuildRelease,
|
||||
}
|
||||
@@ -402,6 +403,17 @@ func checkMergeZips(expected ...string) snapshotBuildInfoChecker {
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the snapshot's info contents are ciorrect.
|
||||
//
|
||||
// Both the expected and actual string are both trimmed before comparing.
|
||||
func checkInfoContents(expected string) snapshotBuildInfoChecker {
|
||||
return func(info *snapshotBuildInfo) {
|
||||
info.t.Helper()
|
||||
android.AssertTrimmedStringEquals(info.t, "info contents do not match",
|
||||
expected, info.infoContents)
|
||||
}
|
||||
}
|
||||
|
||||
type resultChecker func(t *testing.T, result *android.TestResult)
|
||||
|
||||
// snapshotTestPreparer registers a preparer that will be used to customize the specified
|
||||
@@ -479,6 +491,9 @@ type snapshotBuildInfo struct {
|
||||
// The contents of the versioned Android.bp file
|
||||
androidVersionedBpContents string
|
||||
|
||||
// The contents of the info file.
|
||||
infoContents string
|
||||
|
||||
// The paths, relative to the snapshot root, of all files and directories copied into the
|
||||
// snapshot.
|
||||
snapshotContents []string
|
||||
|
150
sdk/update.go
150
sdk/update.go
@@ -15,6 +15,8 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
@@ -219,9 +221,19 @@ func (s *sdk) collectMembers(ctx android.ModuleContext) {
|
||||
exportedComponentsInfo = ctx.OtherModuleProvider(child, android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
|
||||
}
|
||||
|
||||
var container android.SdkAware
|
||||
if parent != ctx.Module() {
|
||||
container = parent.(android.SdkAware)
|
||||
}
|
||||
|
||||
export := memberTag.ExportMember()
|
||||
s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
|
||||
s, memberType, child.(android.SdkAware), export, exportedComponentsInfo,
|
||||
sdkVariant: s,
|
||||
memberType: memberType,
|
||||
variant: child.(android.SdkAware),
|
||||
container: container,
|
||||
export: export,
|
||||
exportedComponentsInfo: exportedComponentsInfo,
|
||||
})
|
||||
|
||||
// Recurse down into the member's dependencies as it may have dependencies that need to be
|
||||
@@ -311,7 +323,7 @@ func versionedSdkMemberName(ctx android.ModuleContext, memberName string, versio
|
||||
|
||||
// buildSnapshot is the main function in this source file. It creates rules to copy
|
||||
// the contents (header files, stub libraries, etc) into the zip file.
|
||||
func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
|
||||
func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) {
|
||||
|
||||
// Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
|
||||
hasLicenses := false
|
||||
@@ -370,9 +382,9 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) andro
|
||||
// Unversioned modules are not required in that case because the numbered version will be a
|
||||
// finalized version of the snapshot that is intended to be kept separate from the
|
||||
generateUnversioned := version == soongSdkSnapshotVersionUnversioned || version == soongSdkSnapshotVersionCurrent
|
||||
snapshotZipFileSuffix := ""
|
||||
snapshotFileSuffix := ""
|
||||
if generateVersioned {
|
||||
snapshotZipFileSuffix = "-" + version
|
||||
snapshotFileSuffix = "-" + version
|
||||
}
|
||||
|
||||
currentBuildRelease := latestBuildRelease()
|
||||
@@ -489,7 +501,7 @@ be unnecessary as every module in the sdk already has its own licenses property.
|
||||
filesToZip := builder.filesToZip
|
||||
|
||||
// zip them all
|
||||
zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotZipFileSuffix)
|
||||
zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotFileSuffix)
|
||||
outputZipFile := android.PathForModuleOut(ctx, zipPath).OutputPath
|
||||
outputDesc := "Building snapshot for " + ctx.ModuleName()
|
||||
|
||||
@@ -502,7 +514,7 @@ be unnecessary as every module in the sdk already has its own licenses property.
|
||||
zipFile = outputZipFile
|
||||
desc = outputDesc
|
||||
} else {
|
||||
intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotZipFileSuffix)
|
||||
intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotFileSuffix)
|
||||
zipFile = android.PathForModuleOut(ctx, intermediatePath).OutputPath
|
||||
desc = "Building intermediate snapshot for " + ctx.ModuleName()
|
||||
}
|
||||
@@ -527,7 +539,120 @@ be unnecessary as every module in the sdk already has its own licenses property.
|
||||
})
|
||||
}
|
||||
|
||||
return outputZipFile
|
||||
modules := s.generateInfoData(ctx, memberVariantDeps)
|
||||
|
||||
// Output the modules information as pretty printed JSON.
|
||||
info := newGeneratedFile(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
|
||||
output, err := json.MarshalIndent(modules, "", " ")
|
||||
if err != nil {
|
||||
ctx.ModuleErrorf("error generating %q: %s", info, err)
|
||||
}
|
||||
builder.infoContents = string(output)
|
||||
info.generatedContents.UnindentedPrintf("%s", output)
|
||||
info.build(pctx, ctx, nil)
|
||||
infoPath := info.path
|
||||
installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), infoPath.Base(), infoPath)
|
||||
s.infoFile = android.OptionalPathForPath(installedInfo)
|
||||
|
||||
// Install the zip, making sure that the info file has been installed as well.
|
||||
installedZip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), outputZipFile.Base(), outputZipFile, installedInfo)
|
||||
s.snapshotFile = android.OptionalPathForPath(installedZip)
|
||||
}
|
||||
|
||||
type moduleInfo struct {
|
||||
// The type of the module, e.g. java_sdk_library
|
||||
moduleType string
|
||||
// The name of the module.
|
||||
name string
|
||||
// A list of additional dependencies of the module.
|
||||
deps []string
|
||||
// Additional dynamic properties.
|
||||
dynamic map[string]interface{}
|
||||
}
|
||||
|
||||
func (m *moduleInfo) MarshalJSON() ([]byte, error) {
|
||||
buffer := bytes.Buffer{}
|
||||
|
||||
separator := ""
|
||||
writeObjectPair := func(key string, value interface{}) {
|
||||
buffer.WriteString(fmt.Sprintf("%s%q: ", separator, key))
|
||||
b, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buffer.Write(b)
|
||||
separator = ","
|
||||
}
|
||||
|
||||
buffer.WriteString("{")
|
||||
writeObjectPair("@type", m.moduleType)
|
||||
writeObjectPair("@name", m.name)
|
||||
if m.deps != nil {
|
||||
writeObjectPair("@deps", m.deps)
|
||||
}
|
||||
for _, k := range android.SortedStringKeys(m.dynamic) {
|
||||
v := m.dynamic[k]
|
||||
writeObjectPair(k, v)
|
||||
}
|
||||
buffer.WriteString("}")
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
var _ json.Marshaler = (*moduleInfo)(nil)
|
||||
|
||||
// generateInfoData creates a list of moduleInfo structures that will be marshalled into JSON.
|
||||
func (s *sdk) generateInfoData(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) interface{} {
|
||||
modules := []*moduleInfo{}
|
||||
sdkInfo := moduleInfo{
|
||||
moduleType: "sdk",
|
||||
name: ctx.ModuleName(),
|
||||
dynamic: map[string]interface{}{},
|
||||
}
|
||||
modules = append(modules, &sdkInfo)
|
||||
|
||||
name2Info := map[string]*moduleInfo{}
|
||||
getModuleInfo := func(module android.Module) *moduleInfo {
|
||||
name := module.Name()
|
||||
info := name2Info[name]
|
||||
if info == nil {
|
||||
moduleType := ctx.OtherModuleType(module)
|
||||
// Remove any suffix added when creating modules dynamically.
|
||||
moduleType = strings.Split(moduleType, "__")[0]
|
||||
info = &moduleInfo{
|
||||
moduleType: moduleType,
|
||||
name: name,
|
||||
}
|
||||
name2Info[name] = info
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
for _, memberVariantDep := range memberVariantDeps {
|
||||
propertyName := memberVariantDep.memberType.SdkPropertyName()
|
||||
var list []string
|
||||
if v, ok := sdkInfo.dynamic[propertyName]; ok {
|
||||
list = v.([]string)
|
||||
}
|
||||
|
||||
memberName := memberVariantDep.variant.Name()
|
||||
list = append(list, memberName)
|
||||
sdkInfo.dynamic[propertyName] = android.SortedUniqueStrings(list)
|
||||
|
||||
if memberVariantDep.container != nil {
|
||||
containerInfo := getModuleInfo(memberVariantDep.container)
|
||||
containerInfo.deps = android.SortedUniqueStrings(append(containerInfo.deps, memberName))
|
||||
}
|
||||
|
||||
// Make sure that the module info is created for each module.
|
||||
getModuleInfo(memberVariantDep.variant)
|
||||
}
|
||||
|
||||
for _, memberName := range android.SortedStringKeys(name2Info) {
|
||||
info := name2Info[memberName]
|
||||
modules = append(modules, info)
|
||||
}
|
||||
|
||||
return modules
|
||||
}
|
||||
|
||||
// filterOutComponents removes any item from the deps list that is a component of another item in
|
||||
@@ -1033,6 +1158,10 @@ func (s *sdk) GetAndroidBpContentsForTests() string {
|
||||
return contents.content.String()
|
||||
}
|
||||
|
||||
func (s *sdk) GetInfoContentsForTests() string {
|
||||
return s.builderForTests.infoContents
|
||||
}
|
||||
|
||||
func (s *sdk) GetUnversionedAndroidBpContentsForTests() string {
|
||||
contents := &generatedContents{}
|
||||
generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
|
||||
@@ -1087,6 +1216,8 @@ type snapshotBuilder struct {
|
||||
|
||||
// The target build release for which the snapshot is to be generated.
|
||||
targetBuildRelease *buildRelease
|
||||
|
||||
infoContents string
|
||||
}
|
||||
|
||||
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
|
||||
@@ -1322,6 +1453,11 @@ type sdkMemberVariantDep struct {
|
||||
// The variant that is added to the sdk.
|
||||
variant android.SdkAware
|
||||
|
||||
// The optional container of this member, i.e. the module that is depended upon by the sdk
|
||||
// (possibly transitively) and whose dependency on this module is why it was added to the sdk.
|
||||
// Is nil if this a direct dependency of the sdk.
|
||||
container android.SdkAware
|
||||
|
||||
// True if the member should be exported, i.e. accessible, from outside the sdk.
|
||||
export bool
|
||||
|
||||
|
Reference in New Issue
Block a user