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.common
18 
19 import com.android.tools.metalava.reporter.Baseline
20 import com.github.ajalt.clikt.core.GroupableOption
21 import com.github.ajalt.clikt.core.ParameterHolder
22 import com.github.ajalt.clikt.parameters.groups.OptionGroup
23 import com.github.ajalt.clikt.parameters.options.option
24 import java.io.File
25 
26 /**
27  * Manages options needed to create a [Baseline] object.
28  *
29  * Ideally, this would just be a plain [OptionGroup] that is added to another [OptionGroup] that
30  * needs a [Baseline]. Unfortunately, Clikt does not support [OptionGroup]s inside of [OptionGroup]s
31  * so instead this just adds the options to the [containingGroup].
32  *
33  * @param containingGroup the [OptionGroup] to which this will add options.
34  */
35 class BaselineOptionsMixin(
36     private val containingGroup: OptionGroup,
37     executionEnvironment: ExecutionEnvironment,
38     baselineOptionName: String,
39     updateBaselineOptionName: String,
<lambda>null40     defaultBaselineFileProvider: () -> File? = { null },
41     issueType: String,
42     description: String,
43     commonBaselineOptions: CommonBaselineOptions,
44 ) : ParameterHolder {
45 
registerOptionnull46     override fun registerOption(option: GroupableOption) {
47         // Register the option with the actual [OptionGroup].
48         containingGroup.registerOption(option)
49     }
50 
51     private val baselineFile by
52         containingGroup
53             .option(
54                 baselineOptionName,
55                 help =
56                     """
57                         An optional baseline file that contains a list of known $issueType issues
58                         which should be ignored. If this does not exist and
59                         $updateBaselineOptionName is not specified then it will be created and
60                         populated with all the known $issueType issues.
61                     """
62                         .trimIndent(),
63             )
64             .existingFile()
65             .allowStructuredOptionName()
66 
67     private val updateBaselineFile by
68         containingGroup
69             .option(
70                 updateBaselineOptionName,
71                 help =
72                     """
73                         An optional file into which a list of the latest $issueType issues found
74                         will be written. If $baselineOptionName is specified then any issues listed
75                         in there will be copied into this file; that minimizes the amount of churn
76                         in the baseline file when updating by not removing legacy issues that have
77                         been fixed. If $ARG_DELETE_EMPTY_BASELINES is specified and this baseline is
78                         empty then the file will be deleted.
79                     """
80                         .trimIndent(),
81             )
82             .newOrExistingFile()
83             .allowStructuredOptionName()
84 
85     val baseline by
<lambda>null86         lazy(LazyThreadSafetyMode.NONE) {
87             Baseline.Builder()
88                 .apply {
89                     this.description = description
90                     file = baselineFile ?: defaultBaselineFileProvider()
91                     updateFile = updateBaselineFile
92                     headerComment =
93                         if (executionEnvironment.isBuildingAndroid())
94                             "// See tools/metalava/API-LINT.md for how to update this file.\n\n"
95                         else ""
96                 }
97                 .build(commonBaselineOptions.baselineConfig)
98         }
99 }
100