• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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