1 /* <lambda>null2 * Copyright (C) 2025 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.OptionsDelegate 20 import com.android.tools.metalava.cli.common.MetalavaSubCommand 21 import com.android.tools.metalava.cli.common.existingFile 22 import com.android.tools.metalava.cli.common.newOrExistingFile 23 import com.android.tools.metalava.cli.common.stderr 24 import com.android.tools.metalava.cli.common.stdin 25 import com.android.tools.metalava.cli.common.stdout 26 import com.android.tools.metalava.model.Codebase 27 import com.android.tools.metalava.model.noOpAnnotationManager 28 import com.android.tools.metalava.model.text.ApiFile 29 import com.android.tools.metalava.model.text.FileFormat 30 import com.android.tools.metalava.model.text.SignatureFile 31 import com.android.tools.metalava.model.text.SignatureWriter 32 import com.android.tools.metalava.model.text.createFilteringVisitorForSignatures 33 import com.android.tools.metalava.model.visitors.ApiPredicate 34 import com.android.tools.metalava.model.visitors.ApiType 35 import com.android.tools.metalava.reporter.BasicReporter 36 import com.github.ajalt.clikt.parameters.arguments.argument 37 import com.github.ajalt.clikt.parameters.arguments.multiple 38 import com.github.ajalt.clikt.parameters.groups.provideDelegate 39 import com.github.ajalt.clikt.parameters.options.option 40 import java.io.PrintWriter 41 42 class SignatureCatCommand : 43 MetalavaSubCommand( 44 help = 45 """ 46 Cats signature files. 47 48 Reads signature files either provided on the command line, or in stdin into a 49 combined API surface and then writes it out to either the output file provided on 50 the command line or to stdout according to the format options. The resulting output 51 will be different to the input if the input does not already conform to the selected 52 format. 53 """ 54 .trimIndent(), 55 printHelpOnEmptyArgs = false, 56 ) { 57 58 private val formatOptions by SignatureFormatOptions(migratingAllowed = true) 59 60 private val files by 61 argument( 62 name = "<files>", 63 help = 64 """ 65 Signature files to read, if not specified then they stdin is read instead. 66 """ 67 .trimIndent(), 68 ) 69 .existingFile() 70 .multiple() 71 72 private val outputFile by 73 option( 74 names = arrayOf("--output-file"), 75 help = 76 """ 77 File to write the signature output to. If not specified stdout will be used. 78 """ 79 .trimIndent() 80 ) 81 .newOrExistingFile() 82 83 override fun run() { 84 // Make sure that none of the code called by this command accesses the global `options` 85 // property. 86 OptionsDelegate.disallowAccess() 87 88 val outputFormat = formatOptions.fileFormat 89 90 val signatureFiles = 91 if (files.isEmpty()) { 92 // If no files are provided on the command line then read from stdin. 93 listOf(SignatureFile.fromStream("<stdin>", stdin)) 94 } else { 95 SignatureFile.fromFiles(files) 96 } 97 98 val codebase = read(signatureFiles) 99 (outputFile?.printWriter() ?: stdout).use { outputWriter -> 100 write(codebase, outputFormat, outputWriter) 101 } 102 } 103 104 private fun read(signatureFiles: List<SignatureFile>) = 105 ApiFile.parseApi( 106 signatureFiles, 107 Codebase.Config( 108 annotationManager = noOpAnnotationManager, 109 reporter = BasicReporter(stderr), 110 ), 111 ) 112 113 private fun write(codebase: Codebase, outputFormat: FileFormat, printWriter: PrintWriter) { 114 val signatureWriter = 115 SignatureWriter( 116 writer = printWriter, 117 fileFormat = outputFormat, 118 ) 119 120 // Create a visitor suitable for writing signatures. It will ensure correct ordering for 121 // signature files for the outputFormat. 122 val apiWriter = 123 createFilteringVisitorForSignatures( 124 delegate = signatureWriter, 125 fileFormat = outputFormat, 126 apiType = ApiType.ALL, 127 preFiltered = true, 128 showUnannotated = true, 129 apiPredicateConfig = ApiPredicate.Config(), 130 ) 131 132 codebase.accept(apiWriter) 133 } 134 } 135