| // Copyright 2022 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package com.google.devtools.build.lib.bazel.bzlmod.modcommand; |
| |
| import static java.util.Arrays.stream; |
| import static java.util.stream.Collectors.joining; |
| |
| import com.google.common.base.Ascii; |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.bazel.bzlmod.ModuleKey; |
| import com.google.devtools.build.lib.bazel.bzlmod.modcommand.ExtensionArg.CommaSeparatedExtensionArgListConverter; |
| import com.google.devtools.build.lib.bazel.bzlmod.modcommand.ModuleArg.CommaSeparatedModuleArgListConverter; |
| import com.google.devtools.build.lib.bazel.bzlmod.modcommand.ModuleArg.ModuleArgConverter; |
| import com.google.devtools.common.options.EnumConverter; |
| import com.google.devtools.common.options.Option; |
| import com.google.devtools.common.options.OptionDocumentationCategory; |
| import com.google.devtools.common.options.OptionEffectTag; |
| import com.google.devtools.common.options.OptionsBase; |
| |
| /** Options for ModCommand */ |
| public class ModOptions extends OptionsBase { |
| |
| @Option( |
| name = "from", |
| defaultValue = "<root>", |
| converter = CommaSeparatedModuleArgListConverter.class, |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "The module(s) starting from which the dependency graph query will be displayed. Check" |
| + " each query’s description for the exact semantics. Defaults to <root>.\n") |
| public ImmutableList<ModuleArg> modulesFrom; |
| |
| @Option( |
| name = "verbose", |
| defaultValue = "false", |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "The queries will also display the reason why modules were resolved to their current" |
| + " version (if changed). Defaults to true only for the explain query.") |
| public boolean verbose; |
| |
| @Option( |
| name = "include_unused", |
| defaultValue = "false", |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "The queries will also take into account and display the unused modules, which are not" |
| + " present in the module resolution graph after selection (due to the" |
| + " Minimal-Version Selection or override rules). This can have different effects for" |
| + " each of the query types i.e. include new paths in the all_paths command, or extra" |
| + " dependants in the explain command.") |
| public boolean includeUnused; |
| |
| @Option( |
| name = "extension_filter", |
| defaultValue = "null", |
| converter = CommaSeparatedExtensionArgListConverter.class, |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "Only display the usages of these module extensions and the repos generated by them if" |
| + " their respective flags are set. If set, the result graph will only include paths" |
| + " that contain modules using the specified extensions. An empty list disables the" |
| + " filter, effectively specifying all possible extensions.") |
| public ImmutableList<ExtensionArg> extensionFilter; |
| |
| @Option( |
| name = "extension_info", |
| defaultValue = "hidden", |
| converter = ExtensionShowConverter.class, |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "Specify how much detail about extension usages to include in the query result." |
| + " \"Usages\" will only show the extensions names, \"repos\" will also include repos" |
| + " imported with use_repo, and \"all\" will also show the other repositories" |
| + " generated by extensions.\n") |
| public ExtensionShow extensionInfo; |
| |
| @Option( |
| name = "base_module", |
| defaultValue = "<root>", |
| converter = ModuleArgConverter.class, |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = "Specify a module relative to which the specified target repos will be interpreted.") |
| public ModuleArg baseModule; |
| |
| @Option( |
| name = "extension_usages", |
| defaultValue = "", |
| converter = CommaSeparatedModuleArgListConverter.class, |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "Specify modules whose extension usages will be displayed in the show_extension query.") |
| public ImmutableList<ModuleArg> extensionUsages; |
| |
| @Option( |
| name = "depth", |
| defaultValue = "-1", |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "Maximum display depth of the dependency tree. A depth of 1 displays the direct" |
| + " dependencies, for example. For tree, path and all_paths it defaults to" |
| + " Integer.MAX_VALUE, while for deps and explain it defaults to 1 (only displays" |
| + " direct deps of the root besides the target leaves and their parents).\n") |
| public int depth; |
| |
| @Option( |
| name = "cycles", |
| defaultValue = "false", |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "Points out dependency cycles inside the displayed tree, which are normally ignored by" |
| + " default.") |
| public boolean cycles; |
| |
| @Option( |
| name = "include_builtin", |
| defaultValue = "false", |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "Include built-in modules in the dependency graph. Disabled by default because it is" |
| + " quite noisy.") |
| public boolean includeBuiltin; |
| |
| @Option( |
| name = "charset", |
| defaultValue = "utf8", |
| converter = CharsetConverter.class, |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "Chooses the character set to use for the tree. Only affects text output. Valid values" |
| + " are \"utf8\" or \"ascii\". Default is \"utf8\"") |
| public Charset charset; |
| |
| @Option( |
| name = "output", |
| defaultValue = "text", |
| converter = OutputFormatConverter.class, |
| documentationCategory = OptionDocumentationCategory.MOD_COMMAND, |
| effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, |
| help = |
| "The format in which the query results should be printed. Allowed values for query are: " |
| + "text, json, graph") |
| public OutputFormat outputFormat; |
| |
| /** Possible subcommands that can be specified for the `mod` command. */ |
| public enum ModSubcommand { |
| DEPS(true), |
| GRAPH(true), |
| ALL_PATHS(true), |
| PATH(true), |
| EXPLAIN(true), |
| SHOW_REPO(false), |
| SHOW_EXTENSION(false); |
| |
| /** Whether this subcommand produces a graph output. */ |
| private final boolean isGraph; |
| |
| ModSubcommand(boolean isGraph) { |
| this.isGraph = isGraph; |
| } |
| |
| @Override |
| public String toString() { |
| return Ascii.toLowerCase(this.name()); |
| } |
| |
| public boolean isGraph() { |
| return isGraph; |
| } |
| |
| public static String printValues() { |
| return "(" + stream(values()).map(ModSubcommand::toString).collect(joining(", ")) + ")"; |
| } |
| } |
| |
| /** Converts a subcommand string to a properly typed {@link ModSubcommand} */ |
| public static class ModSubcommandConverter extends EnumConverter<ModSubcommand> { |
| public ModSubcommandConverter() { |
| super(ModSubcommand.class, "mod subcommand"); |
| } |
| } |
| |
| enum ExtensionShow { |
| HIDDEN, |
| USAGES, |
| REPOS, |
| ALL |
| } |
| |
| /** Converts an option string to a properly typed {@link ExtensionShow} */ |
| public static class ExtensionShowConverter extends EnumConverter<ExtensionShow> { |
| public ExtensionShowConverter() { |
| super(ExtensionShow.class, "extension show"); |
| } |
| } |
| |
| /** Charset to be used in outputting the `mod` command result. */ |
| public enum Charset { |
| UTF8, |
| ASCII |
| } |
| |
| /** Converts a charset option string to a properly typed {@link Charset} */ |
| public static class CharsetConverter extends EnumConverter<Charset> { |
| public CharsetConverter() { |
| super(Charset.class, "output charset"); |
| } |
| } |
| |
| /** Possible formats of the `mod` command result. */ |
| public enum OutputFormat { |
| TEXT, |
| JSON, |
| GRAPH |
| } |
| |
| /** Converts an output format option string to a properly typed {@link OutputFormat} */ |
| public static class OutputFormatConverter extends EnumConverter<OutputFormat> { |
| public OutputFormatConverter() { |
| super(OutputFormat.class, "output format"); |
| } |
| } |
| |
| /** Returns a {@link ModOptions} filled with default values for testing. */ |
| static ModOptions getDefaultOptions() { |
| ModOptions options = new ModOptions(); |
| options.depth = Integer.MAX_VALUE; |
| options.cycles = false; |
| options.includeUnused = false; |
| options.verbose = false; |
| options.modulesFrom = |
| ImmutableList.of(ModuleArg.SpecificVersionOfModule.create(ModuleKey.ROOT)); |
| options.charset = Charset.UTF8; |
| options.outputFormat = OutputFormat.TEXT; |
| options.extensionFilter = null; |
| options.extensionInfo = ExtensionShow.HIDDEN; |
| return options; |
| } |
| } |