| // Copyright 2014 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.pkgcache; | |
| import com.google.common.base.Splitter; | |
| import com.google.common.base.Strings; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableSet; | |
| import com.google.devtools.build.lib.cmdline.LabelSyntaxException; | |
| import com.google.devtools.build.lib.cmdline.PackageIdentifier; | |
| import com.google.devtools.build.lib.packages.RuleVisibility; | |
| import com.google.devtools.build.lib.util.ResourceConverter; | |
| import com.google.devtools.common.options.Converter; | |
| import com.google.devtools.common.options.Converters; | |
| import com.google.devtools.common.options.Converters.CommaSeparatedNonEmptyOptionListConverter; | |
| 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.OptionMetadataTag; | |
| import com.google.devtools.common.options.OptionsBase; | |
| import com.google.devtools.common.options.OptionsClass; | |
| import com.google.devtools.common.options.OptionsParsingException; | |
| import java.util.List; | |
| import java.util.Objects; | |
| /** Options for configuring Packages -- loading and default behaviors. */ | |
| @OptionsClass | |
| public abstract class PackageOptions extends OptionsBase { | |
| /** Converter for the {@code --default_visibility} option. */ | |
| public static class DefaultVisibilityConverter extends Converter.Contextless<RuleVisibility> { | |
| @Override | |
| public RuleVisibility convert(String input) throws OptionsParsingException { | |
| return switch (input) { | |
| case "public" -> RuleVisibility.PUBLIC; | |
| case "private" -> RuleVisibility.PRIVATE; | |
| default -> | |
| throw new OptionsParsingException( | |
| "Not a valid default visibility: '" + input + "' (should be 'public' or 'private'"); | |
| }; | |
| } | |
| @Override | |
| public String getTypeDescription() { | |
| return "default visibility"; | |
| } | |
| } | |
| /** Converter for globbing threads. */ | |
| public static class ParallelismConverter extends ResourceConverter.IntegerConverter { | |
| public ParallelismConverter() throws OptionsParsingException { | |
| super(/* auto= */ HOST_CPUS_SUPPLIER, /* minValue= */ 1, /* maxValue= */ Integer.MAX_VALUE); | |
| } | |
| } | |
| @Option( | |
| name = "package_path", | |
| defaultValue = "%workspace%", | |
| converter = Converters.ColonSeparatedOptionListConverter.class, | |
| documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "A colon-separated list of where to look for packages. " | |
| + "Elements beginning with '%workspace%' are relative to the enclosing " | |
| + "workspace. If omitted or empty, the default is the output of " | |
| + "'bazel info default-package-path'.") | |
| public abstract List<String> getPackagePath(); | |
| public abstract void setPackagePath(List<String> value); | |
| @Option( | |
| name = "show_loading_progress", | |
| defaultValue = "true", | |
| documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = "If enabled, causes Bazel to print \"Loading package:\" messages.") | |
| public abstract boolean getShowLoadingProgress(); | |
| public abstract void setShowLoadingProgress(boolean value); | |
| @Option( | |
| name = "deleted_packages", | |
| allowMultiple = true, | |
| defaultValue = "null", | |
| converter = CommaSeparatedPackageNameListConverter.class, | |
| documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "A comma-separated list of names of packages which the " | |
| + "build system will consider non-existent, even if they are " | |
| + "visible somewhere on the package path.\n" | |
| + "Use this option when deleting a subpackage 'x/y' of an " | |
| + "existing package 'x'. For example, after deleting x/y/BUILD " | |
| + "in your client, the build system may complain if it " | |
| + "encounters a label '//x:y/z' if that is still provided by another " | |
| + "package_path entry. Specifying --deleted_packages x/y avoids this " | |
| + "problem.") | |
| public abstract List<PackageIdentifier> getDeletedPackages(); | |
| @Option( | |
| name = "default_visibility", | |
| defaultValue = "private", | |
| converter = DefaultVisibilityConverter.class, | |
| documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "Default visibility for packages that don't set it explicitly ('public' or 'private').") | |
| public abstract RuleVisibility getDefaultVisibility(); | |
| public abstract void setDefaultVisibility(RuleVisibility value); | |
| @Option( | |
| name = "incompatible_enforce_config_setting_visibility", | |
| // TODO(b/179944632): set this and --incompatible_config_setting_private_default_visibility | |
| // to true, then make these no-ops, then remove. | |
| defaultValue = "true", | |
| documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS, | |
| effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS}, | |
| metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE}, | |
| help = | |
| "If true, enforce config_setting visibility restrictions. If false, every " | |
| + "config_setting is visible to every target. See " | |
| + "https://github.com/bazelbuild/bazel/issues/12932.") | |
| public abstract boolean getEnforceConfigSettingVisibility(); | |
| @Option( | |
| name = "incompatible_config_setting_private_default_visibility", | |
| defaultValue = "false", | |
| documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS, | |
| effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS}, | |
| metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE}, | |
| help = | |
| "If incompatible_enforce_config_setting_visibility=false, this is a noop. Else, if this" | |
| + " flag is false, any config_setting without an explicit visibility attribute is" | |
| + " //visibility:public. If this flag is true, config_setting follows the same" | |
| + " visibility logic as all other rules. See" | |
| + " https://github.com/bazelbuild/bazel/issues/12933.") | |
| public abstract boolean getConfigSettingPrivateDefaultVisibility(); | |
| @Option( | |
| name = "legacy_globbing_threads", | |
| defaultValue = "100", | |
| converter = ParallelismConverter.class, | |
| documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "Number of threads to use for glob evaluation. Takes " | |
| + ResourceConverter.FLAG_SYNTAX | |
| + ". \"auto\" means to use a reasonable value derived from the machine's hardware" | |
| + " profile (e.g. the number of processors).") | |
| public abstract int getGlobbingThreads(); | |
| public abstract void setGlobbingThreads(int value); | |
| @Option( | |
| name = "experimental_max_directories_to_eagerly_visit_in_globbing", | |
| defaultValue = "-1", | |
| documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "If non-negative, the first time a glob is evaluated in a package, the subdirectories of" | |
| + " the package will be traversed in order to warm filesystem caches and compensate" | |
| + " for lack of parallelism in globbing. At most this many directories will be" | |
| + " visited.") | |
| public abstract int getMaxDirectoriesToEagerlyVisitInGlobbing(); | |
| @Option( | |
| name = "fetch", | |
| defaultValue = "true", | |
| documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "Allows the command to fetch external dependencies. If set to false, the command will" | |
| + " utilize any cached version of the dependency, and if none exists, the command" | |
| + " will result in failure.") | |
| public abstract boolean getFetch(); | |
| @Option( | |
| name = "experimental_check_output_files", | |
| defaultValue = "true", | |
| documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "Check for modifications made to the output files of a build. Consider setting " | |
| + "this flag to false if you don't expect these files to change outside of bazel " | |
| + "since it will speed up subsequent runs as they won't have to check a " | |
| + "previous run's cache.") | |
| public abstract boolean getCheckOutputFiles(); | |
| public abstract void setCheckOutputFiles(boolean value); | |
| @Option( | |
| name = "experimental_check_external_other_files", | |
| defaultValue = "true", | |
| documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, | |
| effectTags = {OptionEffectTag.UNKNOWN}, | |
| help = | |
| "Check for modifications made to the non-output, non-repo external files, e.g. host" | |
| + " files.") | |
| public abstract boolean getCheckExternalOtherFiles(); | |
| public abstract void setCheckExternalOtherFiles(boolean value); | |
| // TODO(https://github.com/bazelbuild/bazel/issues/25539) - at present, lazy macro expansion is | |
| // incompatible with non-finalizer use of native.existing_rules(). Once we can load all packages | |
| // in lazy macro expansion mode, we might evolve this option to be an allowlist/denylist for | |
| // performance reasons - which would mean supporting negation or package_group()-style | |
| // subpackage patterns. | |
| @Option( | |
| name = "experimental_lazy_macro_expansion_packages", | |
| defaultValue = "", | |
| converter = LazyMacroExpansionPackages.OptionConverter.class, | |
| documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, | |
| effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS, OptionEffectTag.LOSES_INCREMENTAL_STATE}, | |
| metadataTags = {OptionMetadataTag.EXPERIMENTAL}, | |
| help = "List of packages in which symbolic macro are expanded only if necessary.") | |
| public abstract LazyMacroExpansionPackages getLazyMacroExpansionPackages(); | |
| public abstract void setLazyMacroExpansionPackages(LazyMacroExpansionPackages value); | |
| /** A converter from strings containing comma-separated names of packages to lists of strings. */ | |
| public static class CommaSeparatedPackageNameListConverter | |
| extends Converter.Contextless<List<PackageIdentifier>> { | |
| private static final Splitter COMMA_SPLITTER = Splitter.on(','); | |
| @Override | |
| public List<PackageIdentifier> convert(String input) throws OptionsParsingException { | |
| if (Strings.isNullOrEmpty(input)) { | |
| return ImmutableList.of(); | |
| } | |
| ImmutableList.Builder<PackageIdentifier> list = ImmutableList.builder(); | |
| for (String s : COMMA_SPLITTER.split(input)) { | |
| try { | |
| list.add(PackageIdentifier.parse(s)); | |
| } catch (LabelSyntaxException e) { | |
| throw new OptionsParsingException(e.getMessage()); | |
| } | |
| } | |
| return list.build(); | |
| } | |
| @Override | |
| public String getTypeDescription() { | |
| return "comma-separated list of package names"; | |
| } | |
| } | |
| public ImmutableSet<PackageIdentifier> getDeletedPackagesOrEmptySet() { | |
| if (getDeletedPackages() == null) { | |
| return ImmutableSet.of(); | |
| } | |
| return ImmutableSet.copyOf(getDeletedPackages()); | |
| } | |
| /** | |
| * The set of packages in which symbolic macros are to be expanded lazily. Used by Skyframe and by | |
| * PackageLoader. | |
| */ | |
| public interface LazyMacroExpansionPackages { | |
| /** | |
| * A {@link LazyMacroExpansionPackages} indicating that no packages should have symbolic macros | |
| * expanded lazily. | |
| */ | |
| public static final LazyMacroExpansionPackages NONE = | |
| new LazyMacroExpansionPackagesSet(ImmutableSet.of()); | |
| /** | |
| * A {@link LazyMacroExpansionPackages} indicating that all packages should have symbolic macros | |
| * expanded lazily. | |
| */ | |
| public static final LazyMacroExpansionPackages ALL = | |
| new LazyMacroExpansionPackages() { | |
| @Override | |
| public boolean contains(PackageIdentifier packageId) { | |
| return true; | |
| } | |
| }; | |
| /** Returns true if symbolic macros in the given package should be expanded lazily. */ | |
| boolean contains(PackageIdentifier packageId); | |
| /** {@link Converter} for {@link LazyMacroExpansionPackages}. */ | |
| public static class OptionConverter extends Converter.Contextless<LazyMacroExpansionPackages> { | |
| private static final CommaSeparatedNonEmptyOptionListConverter stringConverter = | |
| new CommaSeparatedNonEmptyOptionListConverter(); | |
| @Override | |
| public LazyMacroExpansionPackages convert(String input) throws OptionsParsingException { | |
| ImmutableList<String> strings = stringConverter.convert(input); | |
| if (strings.isEmpty()) { | |
| return LazyMacroExpansionPackages.NONE; | |
| } else if (strings.contains("*")) { | |
| return LazyMacroExpansionPackages.ALL; | |
| } else { | |
| ImmutableSet.Builder<PackageIdentifier> packageIds = ImmutableSet.builder(); | |
| for (String s : strings) { | |
| try { | |
| packageIds.add(PackageIdentifier.parse(s)); | |
| } catch (LabelSyntaxException e) { | |
| throw new OptionsParsingException(e.getMessage()); | |
| } | |
| } | |
| return new LazyMacroExpansionPackagesSet(packageIds.build()); | |
| } | |
| } | |
| @Override | |
| public String getTypeDescription() { | |
| return "comma-separated list of package names; or '*' to indicate all packages"; | |
| } | |
| } | |
| } | |
| private static final class LazyMacroExpansionPackagesSet implements LazyMacroExpansionPackages { | |
| private final ImmutableSet<PackageIdentifier> packageIds; | |
| private LazyMacroExpansionPackagesSet(ImmutableSet<PackageIdentifier> packageIds) { | |
| this.packageIds = packageIds; | |
| } | |
| @Override | |
| public boolean contains(PackageIdentifier packageId) { | |
| return packageIds.contains(packageId); | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| return o instanceof LazyMacroExpansionPackagesSet other | |
| && Objects.equals(packageIds, other.packageIds); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return Objects.hashCode(packageIds); | |
| } | |
| @Override | |
| public String toString() { | |
| return String.format("LazyMacroExpansionPackages[%s]", packageIds); | |
| } | |
| } | |
| } |