1 /*
2  * 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.lint
18 
19 import com.android.tools.metalava.cli.common.BaselineOptionsMixin
20 import com.android.tools.metalava.cli.common.CommonBaselineOptions
21 import com.android.tools.metalava.cli.common.ExecutionEnvironment
22 import com.android.tools.metalava.cli.common.PreviouslyReleasedApi
23 import com.android.tools.metalava.cli.common.allowStructuredOptionName
24 import com.android.tools.metalava.cli.common.existingFile
25 import com.android.tools.metalava.lint.DefaultLintErrorMessage
26 import com.github.ajalt.clikt.parameters.groups.OptionGroup
27 import com.github.ajalt.clikt.parameters.options.default
28 import com.github.ajalt.clikt.parameters.options.flag
29 import com.github.ajalt.clikt.parameters.options.multiple
30 import com.github.ajalt.clikt.parameters.options.option
31 
32 const val ARG_API_LINT = "--api-lint"
33 const val ARG_API_LINT_PREVIOUS_API = "--api-lint-previous-api"
34 const val ARG_ERROR_MESSAGE_API_LINT = "--error-message:api-lint"
35 
36 const val ARG_BASELINE_API_LINT = "--baseline:api-lint"
37 const val ARG_UPDATE_BASELINE_API_LINT = "--update-baseline:api-lint"
38 
39 /** The name of the group, can be used in help text to refer to the options in this group. */
40 const val API_LINT_GROUP = "Api Lint"
41 
42 class ApiLintOptions(
43     executionEnvironment: ExecutionEnvironment = ExecutionEnvironment(),
44     commonBaselineOptions: CommonBaselineOptions = CommonBaselineOptions(),
45 ) :
46     OptionGroup(
47         name = API_LINT_GROUP,
48         help =
49             """
50                 Options controlling API linting.
51             """
52                 .trimIndent(),
53     ) {
54 
55     internal val apiLintEnabled: Boolean by
56         option(
57                 ARG_API_LINT,
58                 help =
59                     """
60                         Check API for Android API best practices.
61                     """
62                         .trimIndent(),
63             )
64             .flag()
65 
66     internal val apiLintPreviousApis by
67         option(
68                 ARG_API_LINT_PREVIOUS_API,
69                 help =
70                     """
71                         An API signature file that defines, albeit maybe only partially, a
72                         previously released API.
73 
74                         If the API surface extends another API surface then this must include all
75                         the corresponding signature files in order from the outermost API surface
76                         that does not extend any API surface to the innermost one that represents
77                         the API surface being generated.
78 
79                         API Lint issues found in the previously released API will be ignored.
80                      """
81                         .trimIndent(),
82             )
83             .existingFile()
84             .multiple()
85 
86     /**
87      * The optional [PreviouslyReleasedApi]. If provided then only API lint issues which are new
88      * since that API was released will be reported.
89      */
90     internal val previouslyReleasedApi by
<lambda>null91         lazy(LazyThreadSafetyMode.NONE) {
92             PreviouslyReleasedApi.optionalPreviouslyReleasedApi(
93                 ARG_API_LINT_PREVIOUS_API,
94                 apiLintPreviousApis
95             )
96         }
97 
98     /**
99      * If set, metalava will show this error message when "API lint" (i.e. [ARG_API_LINT]) fails.
100      */
101     internal val errorMessage: String? by
102         option(
103                 ARG_ERROR_MESSAGE_API_LINT,
104                 help =
105                     """
106                     If set, this is output when errors are detected in $ARG_API_LINT.
107                 """
108                         .trimIndent(),
109                 metavar = "<message>",
110             )
111             .default(DefaultLintErrorMessage, defaultForHelp = "")
112             .allowStructuredOptionName()
113 
114     private val baselineOptionsMixin =
115         BaselineOptionsMixin(
116             containingGroup = this,
117             executionEnvironment,
118             baselineOptionName = ARG_BASELINE_API_LINT,
119             updateBaselineOptionName = ARG_UPDATE_BASELINE_API_LINT,
120             issueType = "API lint",
121             description = "api-lint",
122             commonBaselineOptions = commonBaselineOptions,
123         )
124 
125     internal val baseline by baselineOptionsMixin::baseline
126 }
127