1 /* <lambda>null2 * Copyright (C) 2023 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.signature 18 19 import com.android.tools.metalava.JDiffXmlWriter 20 import com.android.tools.metalava.OptionsDelegate 21 import com.android.tools.metalava.cli.common.DefaultSignatureFileLoader 22 import com.android.tools.metalava.cli.common.MetalavaSubCommand 23 import com.android.tools.metalava.cli.common.existingFile 24 import com.android.tools.metalava.cli.common.newFile 25 import com.android.tools.metalava.cli.common.progressTracker 26 import com.android.tools.metalava.cli.common.stderr 27 import com.android.tools.metalava.createFilteringVisitorForJDiffWriter 28 import com.android.tools.metalava.createReportFile 29 import com.android.tools.metalava.model.Codebase 30 import com.android.tools.metalava.model.CodebaseFragment 31 import com.android.tools.metalava.model.FilterPredicate 32 import com.android.tools.metalava.model.annotation.DefaultAnnotationManager 33 import com.android.tools.metalava.model.text.FileFormat 34 import com.android.tools.metalava.model.text.SignatureFile 35 import com.android.tools.metalava.model.text.SnapshotDeltaMaker 36 import com.android.tools.metalava.model.visitors.ApiFilters 37 import com.android.tools.metalava.reporter.BasicReporter 38 import com.github.ajalt.clikt.parameters.arguments.argument 39 import com.github.ajalt.clikt.parameters.options.convert 40 import com.github.ajalt.clikt.parameters.options.flag 41 import com.github.ajalt.clikt.parameters.options.option 42 43 class SignatureToJDiffCommand : 44 MetalavaSubCommand( 45 help = 46 """ 47 Convert an API signature file into a file in the JDiff XML format. 48 """ 49 .trimIndent() 50 ) { 51 52 private val strip by 53 option( 54 help = 55 """ 56 Determines whether types that are not defined within the input signature 57 file should be stripped from the output or not. This does not include 58 super class types, i.e. the `extends` attribute in the generated JDiff file. 59 Historically, they have not been filtered. 60 """ 61 .trimIndent() 62 ) 63 .flag("--no-strip", default = false, defaultForHelp = "false") 64 65 private val formatForLegacyFiles by 66 option( 67 "--format-for-legacy-files", 68 metavar = "<format-specifier>", 69 help = 70 """ 71 Optional format to use when reading legacy, i.e. no longer supported, format 72 versions. Forces the signature file to be parsed as if it was in this 73 format. 74 75 This is provided primarily to allow version 1.0 files, which had no header, 76 to be parsed as if they were 2.0 files (by specifying 77 `--format-for-legacy-files=2.0`) so that version 1.0 files can still be read 78 even though metalava no longer supports version 1.0 files specifically. That 79 is effectively what metalava did anyway before it removed support for 80 version 1.0 files so should work reasonably well. 81 82 Applies to both `--base-api` and `<api-file>`. 83 """ 84 .trimIndent() 85 ) 86 .convert { specifier -> FileFormat.parseSpecifier(specifier) } 87 88 private val baseApiFile by 89 option( 90 "--base-api", 91 metavar = "<base-api-file>", 92 help = 93 """ 94 Optional base API file. If provided then the output will only include API 95 items that are not in this file. 96 """ 97 .trimIndent() 98 ) 99 .existingFile() 100 101 private val apiFile by 102 argument( 103 name = "<api-file>", 104 help = 105 """ 106 API signature file to convert to the JDiff XML format. 107 """ 108 .trimIndent() 109 ) 110 .existingFile() 111 112 private val xmlFile by 113 argument( 114 name = "<xml-file>", 115 help = 116 """ 117 Output JDiff XML format file. 118 """ 119 .trimIndent() 120 ) 121 .newFile() 122 123 override fun run() { 124 // Make sure that none of the code called by this command accesses the global `options` 125 // property. 126 OptionsDelegate.disallowAccess() 127 128 val annotationManager = DefaultAnnotationManager() 129 val codebaseConfig = 130 Codebase.Config( 131 annotationManager = annotationManager, 132 reporter = BasicReporter(stderr), 133 ) 134 val signatureFileLoader = 135 DefaultSignatureFileLoader( 136 codebaseConfig = codebaseConfig, 137 formatForLegacyFiles = formatForLegacyFiles, 138 ) 139 140 val signatureApi = signatureFileLoader.load(SignatureFile.fromFiles(apiFile)) 141 142 val strip = strip 143 val apiEmit = FilterPredicate { it.emit } 144 val apiReference = if (strip) apiEmit else FilterPredicate { true } 145 val apiFilters = ApiFilters(emit = apiEmit, reference = apiReference) 146 val baseFile = baseApiFile 147 148 val signatureFragment = 149 CodebaseFragment.create(signatureApi) { delegate -> 150 createFilteringVisitorForJDiffWriter( 151 delegate, 152 apiFilters = apiFilters, 153 preFiltered = signatureApi.preFiltered && !strip, 154 showUnannotated = false, 155 // Historically, the super class type has not been filtered when generating 156 // JDiff files, so do not filter here even though it could result in undefined 157 // types being included in the JDiff file. 158 filterSuperClassType = false, 159 ) 160 } 161 162 val outputFragment = 163 if (baseFile != null) { 164 // Convert base on a diff 165 val baseApi = signatureFileLoader.load(SignatureFile.fromFiles(baseFile)) 166 SnapshotDeltaMaker.createDelta(baseApi, signatureFragment) 167 } else { 168 signatureFragment 169 } 170 171 // See JDiff's XMLToAPI#nameAPI 172 val apiName = xmlFile.nameWithoutExtension.replace(' ', '_') 173 createReportFile(progressTracker, outputFragment, xmlFile, "JDiff File") { printWriter -> 174 JDiffXmlWriter( 175 writer = printWriter, 176 apiName = apiName, 177 ) 178 } 179 } 180 } 181