blob: 95281dbba3dd4bb1cdfcb64217ec1372a1bd8e03 [file] [log] [blame]
// 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.OptionsParsingException;
import java.util.List;
import java.util.Objects;
/** Options for configuring Packages -- loading and default behaviors. */
public 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 List<String> packagePath;
@Option(
name = "show_loading_progress",
defaultValue = "true",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.UNKNOWN},
help = "If enabled, causes Bazel to print \"Loading package:\" messages.")
public boolean showLoadingProgress;
@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 List<PackageIdentifier> deletedPackages;
@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 RuleVisibility defaultVisibility;
@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 boolean enforceConfigSettingVisibility;
@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 boolean configSettingPrivateDefaultVisibility;
@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 int globbingThreads;
@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 int maxDirectoriesToEagerlyVisitInGlobbing;
@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 boolean fetch;
@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 boolean checkOutputFiles;
@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 boolean checkExternalOtherFiles;
// 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 LazyMacroExpansionPackages lazyMacroExpansionPackages;
/** 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> getDeletedPackages() {
if (deletedPackages == null) {
return ImmutableSet.of();
}
return ImmutableSet.copyOf(deletedPackages);
}
/**
* 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);
}
}
}