1 /* <lambda>null2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.build.dackka 18 19 import com.google.gson.Gson 20 import com.google.gson.GsonBuilder 21 import java.io.File 22 import java.io.FileWriter 23 import java.util.zip.ZipFile 24 import org.gradle.api.DefaultTask 25 import org.gradle.api.artifacts.component.ComponentArtifactIdentifier 26 import org.gradle.api.artifacts.component.ModuleComponentIdentifier 27 import org.gradle.api.file.RegularFileProperty 28 import org.gradle.api.provider.ListProperty 29 import org.gradle.api.tasks.CacheableTask 30 import org.gradle.api.tasks.Input 31 import org.gradle.api.tasks.InputFiles 32 import org.gradle.api.tasks.OutputFile 33 import org.gradle.api.tasks.PathSensitive 34 import org.gradle.api.tasks.PathSensitivity 35 import org.gradle.api.tasks.TaskAction 36 import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier 37 38 @CacheableTask 39 abstract class GenerateMetadataTask : DefaultTask() { 40 41 /** List of artifacts to convert to JSON */ 42 @Input abstract fun getArtifactIds(): ListProperty<ComponentArtifactIdentifier> 43 44 /** List of files corresponding to artifacts in [getArtifactIds] */ 45 @InputFiles 46 @PathSensitive(PathSensitivity.NONE) 47 abstract fun getArtifactFiles(): ListProperty<File> 48 49 /** List of multiplatform artifacts to convert to JSON */ 50 @Input abstract fun getMultiplatformArtifactIds(): ListProperty<ComponentArtifactIdentifier> 51 52 /** List of files corresponding to artifacts in [getMultiplatformArtifactIds] */ 53 @InputFiles 54 @PathSensitive(PathSensitivity.NONE) 55 abstract fun getMultiplatformArtifactFiles(): ListProperty<File> 56 57 /** Location of the generated JSON file */ 58 @get:OutputFile abstract val destinationFile: RegularFileProperty 59 60 @TaskAction 61 fun generate() { 62 val entries = 63 createEntries(getArtifactIds().get(), getArtifactFiles().get(), multiplatform = false) + 64 createEntries( 65 getMultiplatformArtifactIds().get(), 66 getMultiplatformArtifactFiles().get(), 67 multiplatform = true 68 ) 69 70 val gson = 71 if (DEBUG) { 72 GsonBuilder().setPrettyPrinting().create() 73 } else { 74 Gson() 75 } 76 val writer = FileWriter(destinationFile.get().toString()) 77 gson.toJson(entries, writer) 78 writer.close() 79 } 80 81 private fun createEntries( 82 ids: List<ComponentArtifactIdentifier>, 83 artifacts: List<File>, 84 multiplatform: Boolean 85 ): List<MetadataEntry> = 86 ids.indices.mapNotNull { i -> 87 val id = ids[i] 88 val file = artifacts[i] 89 // Only process artifact if it can be cast to ModuleComponentIdentifier. 90 // 91 // In practice, metadata is generated only for docs-public and not docs-tip-of-tree 92 // (where id.componentIdentifier is DefaultProjectComponentIdentifier). 93 if (id.componentIdentifier !is DefaultModuleComponentIdentifier) return@mapNotNull null 94 95 // Created https://github.com/gradle/gradle/issues/21415 to track surfacing 96 // group / module / version in ComponentIdentifier 97 val componentId = (id.componentIdentifier as ModuleComponentIdentifier) 98 99 // Fetch the list of files contained in the .jar file 100 val fileList = 101 ZipFile(file).entries().toList().map { 102 if (multiplatform) { 103 // Paths for multiplatform will start with a directory for the platform 104 // (e.g. 105 // "commonMain"), while Dackka only sees the part of the path after this. 106 it.name.substringAfter("/") 107 } else { 108 it.name 109 } 110 } 111 112 MetadataEntry( 113 groupId = componentId.group, 114 artifactId = componentId.module, 115 releaseNotesUrl = generateReleaseNotesUrl(componentId.group), 116 jarContents = fileList 117 ) 118 } 119 120 private fun generateReleaseNotesUrl(groupId: String): String { 121 val library = groupId.removePrefix("androidx.").replace(".", "-") 122 return "/jetpack/androidx/releases/$library" 123 } 124 125 companion object { 126 private const val DEBUG = false 127 } 128 } 129