1 /* <lambda>null2 * Copyright (C) 2024 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 com.android.tools.metalava.cli.common 18 19 import com.android.SdkConstants 20 import com.android.tools.metalava.model.Codebase 21 import com.android.tools.metalava.model.text.SignatureFile 22 import java.io.File 23 24 /** A previously released API. */ 25 sealed interface PreviouslyReleasedApi { 26 27 /** The set of files defining the previously released API. */ 28 val files: List<File> 29 30 /** The last signature file, if any, defining the previously released API. */ 31 val lastSignatureFile: File? 32 33 /** Load the files into a list of [Codebase]s. */ 34 fun load( 35 jarLoader: (File) -> Codebase, 36 signatureFileLoader: (List<SignatureFile>) -> Codebase, 37 ): Codebase 38 39 override fun toString(): String 40 41 companion object { 42 /** 43 * Create an optional [PreviouslyReleasedApi] instance from the list of [files] passed to 44 * the option [optionName]. 45 * 46 * If [files] is empty then this returns `null`. If [files] contains a mixture of jar and 47 * non-jar files (assumed to be signature files) then it is an error. Otherwise, this will 48 * return a [JarBasedApi] or [SignatureBasedApi] for a list of jar files and a list of 49 * signature files respectively. 50 */ 51 internal fun optionalPreviouslyReleasedApi(optionName: String, files: List<File>) = 52 if (files.isEmpty()) null 53 else { 54 // Partition the files into jar and non-jar files, the latter are assumed to be 55 // signature files. 56 val (jarFiles, signatureFiles) = 57 files.partition { it.path.endsWith(SdkConstants.DOT_JAR) } 58 when { 59 jarFiles.isEmpty() -> SignatureBasedApi.fromFiles(signatureFiles) 60 signatureFiles.isEmpty() -> 61 if (jarFiles.size > 1) 62 throw IllegalStateException( 63 "$optionName: Cannot have more than one jar file, found: ${jarFiles.joinToString()}" 64 ) 65 else JarBasedApi(jarFiles[0]) 66 else -> 67 throw IllegalStateException( 68 "$optionName: Cannot mix jar files (e.g. ${jarFiles.first()}) and signature files (e.g. ${signatureFiles.first()})" 69 ) 70 } 71 } 72 } 73 } 74 75 /** A previously released API defined by jar files. */ 76 data class JarBasedApi(val file: File) : PreviouslyReleasedApi { 77 78 override val files: List<File> = listOf(file) 79 80 /** This does not have any signature files, so it always returns `null`. */ 81 override val lastSignatureFile: File? = null 82 loadnull83 override fun load( 84 jarLoader: (File) -> Codebase, 85 signatureFileLoader: (List<SignatureFile>) -> Codebase, 86 ) = jarLoader(file) 87 88 override fun toString(): String { 89 return file.toString() 90 } 91 } 92 93 /** 94 * A previously released API defined by signature files. 95 * 96 * If a single file is provided then it may be a full API or a delta on another API. If multiple 97 * files are provided then they are expected to be provided in order from the narrowest API to the 98 * widest API, where all but the first files are deltas on the preceding file. 99 */ 100 data class SignatureBasedApi(val signatureFiles: List<SignatureFile>) : PreviouslyReleasedApi { 101 <lambda>null102 override val files: List<File> = signatureFiles.map { it.file } 103 104 override val lastSignatureFile = signatureFiles.last().file 105 loadnull106 override fun load( 107 jarLoader: (File) -> Codebase, 108 signatureFileLoader: (List<SignatureFile>) -> Codebase, 109 ) = signatureFileLoader(signatureFiles) 110 111 override fun toString(): String { 112 return signatureFiles.joinToString(",") { it.file.path } 113 } 114 115 companion object { fromFilesnull116 fun fromFiles(files: List<File>): SignatureBasedApi { 117 val lastIndex = files.size - 1 118 return SignatureBasedApi( 119 files.mapIndexed { index, file -> 120 SignatureFile( 121 file, 122 // The last file is assumed to be for the current API surface. 123 forCurrentApiSurface = index == lastIndex, 124 ) 125 } 126 ) 127 } 128 } 129 } 130