1 /*
2  * 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.common
18 
19 import com.github.ajalt.clikt.core.CliktCommand
20 import com.github.ajalt.clikt.core.context
21 import com.github.ajalt.clikt.parameters.arguments.argument
22 import com.github.ajalt.clikt.parameters.arguments.multiple
23 import com.github.ajalt.clikt.parameters.groups.OptionGroup
24 import com.github.ajalt.clikt.parameters.groups.provideDelegate
25 import com.github.ajalt.clikt.parameters.options.default
26 import com.github.ajalt.clikt.parameters.options.option
27 import com.github.ajalt.clikt.parameters.options.switch
28 
29 const val ARG_QUIET = "--quiet"
30 const val ARG_VERBOSE = "--verbose"
31 
32 enum class Verbosity(val quiet: Boolean = false, val verbose: Boolean = false) {
33     /** Whether to report warnings and other diagnostics along the way. */
34     QUIET(quiet = true),
35 
36     /** Standard output level. */
37     NORMAL,
38 
39     /** Whether to report extra diagnostics along the way. */
40     VERBOSE(verbose = true)
41 }
42 
43 /**
44  * Container for options that need to be processed as early as possible, i.e. before any commands.
45  *
46  * Note this could generate results different from what would happen downstream, e.g. if
47  * `"--verbose"` was used as a flag value, e.g. `--hide --verbose`. But that's not a realistic
48  * problem.
49  */
50 open class EarlyOptions : OptionGroup() {
51 
52     val verbosity: Verbosity by
53         option(
54                 help =
55                     """
56             Set the verbosity of the output.$HARD_NEWLINE
57                 $ARG_QUIET - Only include vital output.$HARD_NEWLINE
58                 $ARG_VERBOSE - Include extra diagnostic output.$HARD_NEWLINE
59             """
60                         .trimIndent()
61             )
62             .switch(
63                 ARG_QUIET to Verbosity.QUIET,
64                 ARG_VERBOSE to Verbosity.VERBOSE,
65             )
66             .default(Verbosity.NORMAL, defaultForHelp = "Neither $ARG_QUIET or $ARG_VERBOSE")
67 
68     companion object {
69         /**
70          * Parse the arguments to extract the early options; ignores any unknown arguments or
71          * options.
72          */
parsenull73         fun parse(args: Array<String>): EarlyOptions {
74             val command = EarlyOptionCommand()
75             command.parse(args)
76             return command.earlyOptions
77         }
78     }
79 
80     /** A command used to parse [EarlyOptions]. */
81     private class EarlyOptionCommand : CliktCommand(treatUnknownOptionsAsArgs = true) {
82         init {
<lambda>null83             context {
84                 // Ignore help options.
85                 helpOptionNames = emptySet()
86             }
87         }
88 
89         /**
90          * Register an argument that will consume all the unknown options and arguments so that they
91          * will not be treated as an error but any collected values will just be ignored.
92          */
93         @Suppress("unused") private val ignored by argument().multiple()
94 
95         val earlyOptions by EarlyOptions()
96 
runnull97         override fun run() {}
98     }
99 }
100