Target pattern parsing cleanup
================
* `TargetPattern#renameRepository` is merged into `TargetPattern.Parser#parse`. This is much less error-prone -- repo mapping should not be an afterthought, but something that should always be applied if possible (sometimes it's not, for example for `blaze query`).
* This also fixes the bug where calling `native.register_toolchains("//:all")` in `@some_repo//:defs.bzl` registers `@//:all` instead of `@some_repo//:all` (see change in RegisteredExecutionPlatformsTest)
* A new class `SignedTargetPattern` is introduced, which can store whether the pattern is positive or negative (with the `sign` method).
* `TargetPatternValue#keys` is greatly simplified thanks to the changes above; the exception throwing is confined to the parsing step, and the construction of `TargetPatternKey` can happen as a separate step, obviating the whole "skykey or exception" dance.
* Following from the above, the //external package now stores registered toolchains and execution platforms as parsed target patterns, instead of simple strings.
Among other things, this would help implement toolchain registration in bzlmod.
PiperOrigin-RevId: 400720457
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java
index 7bb24a88..20f77b8 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternValue.java
@@ -15,6 +15,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Interner;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.cmdline.TargetPattern.Type;
@@ -23,12 +24,10 @@
import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
import com.google.devtools.build.lib.server.FailureDetails.TargetPatterns;
import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
-import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternSkyKeyOrException;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.AbstractSkyKey;
import com.google.devtools.build.skyframe.SkyFunctionName;
-import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.List;
@@ -92,16 +91,15 @@
ImmutableList.builder();
ImmutableList.Builder<PrepareDepsOfPatternSkyKeyException> resultExceptionsBuilder =
ImmutableList.builder();
- Iterable<TargetPatternSkyKeyOrException> keysMaybe =
- TargetPatternValue.keys(patterns, FilteringPolicies.NO_FILTER, offset);
+ TargetPattern.Parser parser = TargetPattern.mainRepoParser(offset);
ImmutableList.Builder<TargetPatternKey> targetPatternKeysBuilder = ImmutableList.builder();
- for (TargetPatternSkyKeyOrException keyMaybe : keysMaybe) {
+ for (String pattern : patterns) {
try {
- SkyKey key = keyMaybe.getSkyKey();
- targetPatternKeysBuilder.add((TargetPatternKey) key.argument());
+ targetPatternKeysBuilder.add(
+ TargetPatternValue.key(
+ SignedTargetPattern.parse(pattern, parser), FilteringPolicies.NO_FILTER));
} catch (TargetParsingException e) {
- resultExceptionsBuilder.add(
- new PrepareDepsOfPatternSkyKeyException(e, keyMaybe.getOriginalPattern()));
+ resultExceptionsBuilder.add(new PrepareDepsOfPatternSkyKeyException(e, pattern));
}
}
// This code path is evaluated only for query universe preloading, and the quadratic cost of
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java
index 8a94bce..9d40971 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunction.java
@@ -87,6 +87,7 @@
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException {
ExtendedEventHandler eventHandler = env.getListener();
+ // TODO(wyv): use the repo mapping of the main repo here.
ImmutableList<SkyKey> skyKeys = getSkyKeys(skyKey, eventHandler);
Map<SkyKey, ValueOrException<TargetParsingException>> tokensByKey =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java
index fb5cca9..107620b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java
@@ -16,7 +16,6 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
-import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -28,7 +27,10 @@
import com.google.devtools.build.lib.bazel.bzlmod.ExternalDepsException;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelConstants;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
+import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
@@ -37,8 +39,10 @@
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.Toolchain;
import com.google.devtools.build.lib.skyframe.PlatformLookupUtil.InvalidPlatformException;
+import com.google.devtools.build.lib.skyframe.TargetPatternUtil.InvalidTargetPatternException;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.util.DetailedExitCode;
+import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
@@ -52,6 +56,10 @@
/** {@link SkyFunction} that returns all registered execution platforms available. */
public class RegisteredExecutionPlatformsFunction implements SkyFunction {
+ @AutoCodec
+ static final FilteringPolicy HAS_PLATFORM_INFO =
+ (Target target, boolean explicit) -> explicit || PlatformLookupUtil.hasPlatformInfo(target);
+
@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env)
@@ -60,34 +68,47 @@
BuildConfigurationValue buildConfigurationValue =
(BuildConfigurationValue)
env.getValue(((RegisteredExecutionPlatformsValue.Key) skyKey).getConfigurationKey());
+ RepositoryMappingValue mainRepoMapping =
+ (RepositoryMappingValue) env.getValue(RepositoryMappingValue.key(RepositoryName.MAIN));
if (env.valuesMissing()) {
return null;
}
BuildConfiguration configuration = buildConfigurationValue.getConfiguration();
- ImmutableList.Builder<String> targetPatternBuilder = new ImmutableList.Builder<>();
+ TargetPattern.Parser mainRepoParser =
+ new TargetPattern.Parser(
+ PathFragment.EMPTY_FRAGMENT,
+ RepositoryName.MAIN,
+ mainRepoMapping.getRepositoryMapping());
+ ImmutableList.Builder<SignedTargetPattern> targetPatternBuilder = new ImmutableList.Builder<>();
// Get the execution platforms from the configuration.
PlatformConfiguration platformConfiguration =
configuration.getFragment(PlatformConfiguration.class);
if (platformConfiguration != null) {
- targetPatternBuilder.addAll(platformConfiguration.getExtraExecutionPlatforms());
+ try {
+ targetPatternBuilder.addAll(
+ TargetPatternUtil.parseAllSigned(
+ platformConfiguration.getExtraExecutionPlatforms(), mainRepoParser));
+ } catch (InvalidTargetPatternException e) {
+ throw new RegisteredExecutionPlatformsFunctionException(
+ new InvalidExecutionPlatformLabelException(e), Transience.PERSISTENT);
+ }
}
// Get the registered execution platforms from the WORKSPACE.
- List<String> workspaceExecutionPlatforms = getWorkspaceExecutionPlatforms(env);
+ ImmutableList<TargetPattern> workspaceExecutionPlatforms = getWorkspaceExecutionPlatforms(env);
if (workspaceExecutionPlatforms == null) {
return null;
}
- targetPatternBuilder.addAll(workspaceExecutionPlatforms);
-
- ImmutableList<String> targetPatterns = targetPatternBuilder.build();
+ targetPatternBuilder.addAll(TargetPatternUtil.toSigned(workspaceExecutionPlatforms));
// Expand target patterns.
ImmutableList<Label> platformLabels;
try {
platformLabels =
- TargetPatternUtil.expandTargetPatterns(env, targetPatterns, HasPlatformInfo.create());
+ TargetPatternUtil.expandTargetPatterns(
+ env, targetPatternBuilder.build(), HAS_PLATFORM_INFO);
if (env.valuesMissing()) {
return null;
}
@@ -113,7 +134,7 @@
*/
@Nullable
@VisibleForTesting
- public static ImmutableList<String> getWorkspaceExecutionPlatforms(Environment env)
+ public static ImmutableList<TargetPattern> getWorkspaceExecutionPlatforms(Environment env)
throws InterruptedException {
PackageValue externalPackageValue =
(PackageValue) env.getValue(PackageValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER));
@@ -231,24 +252,4 @@
super(cause, transience);
}
}
-
- // This class uses AutoValue solely to get default equals/hashCode behavior, which is needed to
- // make skyframe serialization work properly.
- @AutoValue
- @AutoCodec
- abstract static class HasPlatformInfo extends FilteringPolicy {
-
- @Override
- public boolean shouldRetain(Target target, boolean explicit) {
- if (explicit) {
- return true;
- }
- return PlatformLookupUtil.hasPlatformInfo(target);
- }
-
- @AutoCodec.Instantiator
- static HasPlatformInfo create() {
- return new AutoValue_RegisteredExecutionPlatformsFunction_HasPlatformInfo();
- }
- }
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java
index 0b7400c..bd33592 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java
@@ -27,10 +27,15 @@
import com.google.devtools.build.lib.bazel.bzlmod.ExternalDepsException;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelConstants;
+import com.google.devtools.build.lib.cmdline.RepositoryName;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
+import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
import com.google.devtools.build.lib.server.FailureDetails.Toolchain.Code;
+import com.google.devtools.build.lib.skyframe.TargetPatternUtil.InvalidTargetPatternException;
+import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
@@ -54,33 +59,45 @@
BuildConfigurationValue buildConfigurationValue =
(BuildConfigurationValue)
env.getValue(((RegisteredToolchainsValue.Key) skyKey).getConfigurationKey());
+ RepositoryMappingValue mainRepoMapping =
+ (RepositoryMappingValue) env.getValue(RepositoryMappingValue.key(RepositoryName.MAIN));
if (env.valuesMissing()) {
return null;
}
BuildConfiguration configuration = buildConfigurationValue.getConfiguration();
- ImmutableList.Builder<String> targetPatternBuilder = new ImmutableList.Builder<>();
+ TargetPattern.Parser mainRepoParser =
+ new TargetPattern.Parser(
+ PathFragment.EMPTY_FRAGMENT,
+ RepositoryName.MAIN,
+ mainRepoMapping.getRepositoryMapping());
+ ImmutableList.Builder<SignedTargetPattern> targetPatternBuilder = new ImmutableList.Builder<>();
// Get the toolchains from the configuration.
PlatformConfiguration platformConfiguration =
configuration.getFragment(PlatformConfiguration.class);
- targetPatternBuilder.addAll(platformConfiguration.getExtraToolchains());
+ try {
+ targetPatternBuilder.addAll(
+ TargetPatternUtil.parseAllSigned(
+ platformConfiguration.getExtraToolchains(), mainRepoParser));
+ } catch (InvalidTargetPatternException e) {
+ throw new RegisteredToolchainsFunctionException(
+ new InvalidToolchainLabelException(e), Transience.PERSISTENT);
+ }
// Get the registered toolchains from the WORKSPACE.
- ImmutableList<String> workspaceToolchains = getWorkspaceToolchains(env);
+ ImmutableList<TargetPattern> workspaceToolchains = getWorkspaceToolchains(env);
if (workspaceToolchains == null) {
return null;
}
- targetPatternBuilder.addAll(workspaceToolchains);
-
- ImmutableList<String> targetPatterns = targetPatternBuilder.build();
+ targetPatternBuilder.addAll(TargetPatternUtil.toSigned(workspaceToolchains));
// Expand target patterns.
ImmutableList<Label> toolchainLabels;
try {
toolchainLabels =
TargetPatternUtil.expandTargetPatterns(
- env, targetPatterns, FilteringPolicies.ruleType("toolchain", true));
+ env, targetPatternBuilder.build(), FilteringPolicies.ruleTypeExplicit("toolchain"));
if (env.valuesMissing()) {
return null;
}
@@ -106,7 +123,7 @@
*/
@Nullable
@VisibleForTesting
- public static ImmutableList<String> getWorkspaceToolchains(Environment env)
+ public static ImmutableList<TargetPattern> getWorkspaceToolchains(Environment env)
throws InterruptedException {
PackageValue externalPackageValue =
(PackageValue) env.getValue(PackageValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER));
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
index fe79140..081dfd9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
@@ -18,6 +18,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.ResolvedTargets;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.events.Event;
@@ -146,7 +147,9 @@
throws TargetParsingException {
try {
TargetPatternKey key =
- TargetPatternValue.key(targetPattern, FilteringPolicies.NO_FILTER, offset);
+ TargetPatternValue.key(
+ SignedTargetPattern.parse(targetPattern, TargetPattern.mainRepoParser(offset)),
+ FilteringPolicies.NO_FILTER);
return isSimple(key.getParsedPattern())
? new SimpleLookup(targetPattern, key)
: new NormalLookup(targetPattern, key);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetExcludingFilteringPolicy.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetExcludingFilteringPolicy.java
index 4069ea6..ef23fd2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetExcludingFilteringPolicy.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetExcludingFilteringPolicy.java
@@ -17,12 +17,13 @@
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
+import java.util.Objects;
/**
* A filtering policy that excludes multiple single targets. These are not expected to be a part of
* any SkyKey and it's expected that the number of targets is not too large.
*/
-class TargetExcludingFilteringPolicy extends FilteringPolicy {
+class TargetExcludingFilteringPolicy implements FilteringPolicy {
private final ImmutableSet<Label> excludedSingleTargets;
TargetExcludingFilteringPolicy(ImmutableSet<Label> excludedSingleTargets) {
@@ -38,4 +39,21 @@
public String toString() {
return String.format("excludedTargets%s", excludedSingleTargets);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof TargetExcludingFilteringPolicy)) {
+ return false;
+ }
+ TargetExcludingFilteringPolicy that = (TargetExcludingFilteringPolicy) o;
+ return Objects.equals(excludedSingleTargets, that.excludedSingleTargets);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(excludedSingleTargets);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java
index 54d1833..8e8722f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternPhaseFunction.java
@@ -29,6 +29,7 @@
import com.google.devtools.build.lib.cmdline.RepositoryMapping;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.cmdline.ResolvedTargets;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.events.Event;
@@ -41,6 +42,7 @@
import com.google.devtools.build.lib.pkgcache.AbstractRecursivePackageProvider.MissingDepException;
import com.google.devtools.build.lib.pkgcache.CompileOneDependencyTransformer;
import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
+import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
import com.google.devtools.build.lib.pkgcache.LoadingPhaseCompleteEvent;
import com.google.devtools.build.lib.pkgcache.ParsingFailedEvent;
import com.google.devtools.build.lib.pkgcache.TargetParsingCompleteEvent;
@@ -48,7 +50,6 @@
import com.google.devtools.build.lib.repository.ExternalPackageHelper;
import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue.TargetPatternPhaseKey;
import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
-import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternSkyKeyOrException;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyKey;
@@ -107,8 +108,13 @@
// set as build list as well.
ResolvedTargets<Target> testTargets = null;
if (options.getDetermineTests() || options.getBuildTestsOnly()) {
- testTargets = determineTests(env,
- options.getTargetPatterns(), options.getOffset(), options.getTestFilter());
+ testTargets =
+ determineTests(
+ env,
+ options.getTargetPatterns(),
+ options.getOffset(),
+ repositoryMappingValue.getRepositoryMapping(),
+ options.getTestFilter());
Preconditions.checkState(env.valuesMissing() || (testTargets != null));
}
@@ -274,43 +280,34 @@
RepositoryMapping repoMapping,
List<String> failedPatterns)
throws InterruptedException {
-
- ImmutableList.Builder<String> canonicalPatterns = new ImmutableList.Builder<>();
- for (String rawPattern : options.getTargetPatterns()) {
- canonicalPatterns.add(TargetPattern.renameRepository(rawPattern, repoMapping));
- }
-
+ TargetPattern.Parser parser =
+ new TargetPattern.Parser(options.getOffset(), RepositoryName.MAIN, repoMapping);
+ FilteringPolicy policy =
+ options.getBuildManualTests()
+ ? FilteringPolicies.NO_FILTER
+ : FilteringPolicies.FILTER_MANUAL;
List<TargetPatternKey> patternSkyKeys = new ArrayList<>(options.getTargetPatterns().size());
- for (TargetPatternSkyKeyOrException keyOrException :
- TargetPatternValue.keys(
- canonicalPatterns.build(),
- options.getBuildManualTests()
- ? FilteringPolicies.NO_FILTER
- : FilteringPolicies.FILTER_MANUAL,
- options.getOffset())) {
+ for (String pattern : options.getTargetPatterns()) {
try {
- patternSkyKeys.add(keyOrException.getSkyKey());
+ patternSkyKeys.add(
+ TargetPatternValue.key(SignedTargetPattern.parse(pattern, parser), policy));
} catch (TargetParsingException e) {
- failedPatterns.add(keyOrException.getOriginalPattern());
+ failedPatterns.add(pattern);
// We post a PatternExpandingError here - the pattern could not be parsed, so we don't even
// get to run TargetPatternFunction.
- env.getListener().post(
- PatternExpandingError.failed(keyOrException.getOriginalPattern(), e.getMessage()));
+ env.getListener().post(PatternExpandingError.failed(pattern, e.getMessage()));
// We generally skip patterns that don't parse. We report a parsing failed exception to the
// event bus here, but not in determineTests below, which goes through the same list. Note
// that the TargetPatternFunction otherwise reports these events (but only if the target
// pattern could be parsed successfully).
- env.getListener().post(
- new ParsingFailedEvent(keyOrException.getOriginalPattern(), e.getMessage()));
+ env.getListener().post(new ParsingFailedEvent(pattern, e.getMessage()));
try {
env.getValueOrThrow(
TargetPatternErrorFunction.key(e.getMessage()), TargetParsingException.class);
} catch (TargetParsingException ignore) {
// We ignore this. Keep going is active.
}
- env.getListener().handle(
- Event.error(
- "Skipping '" + keyOrException.getOriginalPattern() + "': " + e.getMessage()));
+ env.getListener().handle(Event.error("Skipping '" + pattern + "': " + e.getMessage()));
}
}
@@ -398,16 +395,24 @@
* of targets, handling the filter flags, and expanding test suites.
*
* @param targetPatterns the list of command-line target patterns specified by the user
+ * @param repoMapping the repository mapping to apply to repos in the patterns
* @param testFilter the test filter
*/
private static ResolvedTargets<Target> determineTests(
- Environment env, List<String> targetPatterns, PathFragment offset, TestFilter testFilter)
+ Environment env,
+ List<String> targetPatterns,
+ PathFragment offset,
+ RepositoryMapping repoMapping,
+ TestFilter testFilter)
throws InterruptedException {
+ TargetPattern.Parser parser =
+ new TargetPattern.Parser(offset, RepositoryName.MAIN, repoMapping);
List<TargetPatternKey> patternSkyKeys = new ArrayList<>();
- for (TargetPatternSkyKeyOrException keyOrException :
- TargetPatternValue.keys(targetPatterns, FilteringPolicies.FILTER_TESTS, offset)) {
+ for (String pattern : targetPatterns) {
try {
- patternSkyKeys.add(keyOrException.getSkyKey());
+ patternSkyKeys.add(
+ TargetPatternValue.key(
+ SignedTargetPattern.parse(pattern, parser), FilteringPolicies.FILTER_TESTS));
} catch (TargetParsingException e) {
// Skip.
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternUtil.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternUtil.java
index fd5e61c..411d24e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternUtil.java
@@ -14,70 +14,48 @@
package com.google.devtools.build.lib.skyframe;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern.Sign;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
-import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
+import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
-import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.ValueOrException;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
-/**
- * Utility class to help with evaluating target patterns.
- */
+/** Utility class to help with evaluating target patterns. */
public class TargetPatternUtil {
/**
- * Expand the given {@code targetPatterns}. This handles the needed underlying Skyframe calls (via
- * {@code env}), and will return {@code null} to signal a Skyframe restart.
- */
- @Nullable
- public static ImmutableList<Label> expandTargetPatterns(
- Environment env, List<String> targetPatterns)
- throws InvalidTargetPatternException, InterruptedException {
-
- return expandTargetPatterns(env, targetPatterns, FilteringPolicies.NO_FILTER);
- }
-
- /**
* Expand the given {@code targetPatterns}, using the {@code filteringPolicy}. This handles the
* needed underlying Skyframe calls (via {@code env}), and will return {@code null} to signal a
* Skyframe restart.
*/
@Nullable
public static ImmutableList<Label> expandTargetPatterns(
- Environment env, List<String> targetPatterns, FilteringPolicy filteringPolicy)
+ Environment env, List<SignedTargetPattern> targetPatterns, FilteringPolicy filteringPolicy)
throws InvalidTargetPatternException, InterruptedException {
if (targetPatterns.isEmpty()) {
return ImmutableList.of();
}
- // First parse the patterns, and throw any errors immediately.
- List<TargetPatternValue.TargetPatternKey> patternKeys = new ArrayList<>();
- for (TargetPatternValue.TargetPatternSkyKeyOrException keyOrException :
- TargetPatternValue.keys(targetPatterns, filteringPolicy, PathFragment.EMPTY_FRAGMENT)) {
-
- try {
- patternKeys.add(keyOrException.getSkyKey());
- } catch (TargetParsingException e) {
- throw new InvalidTargetPatternException(keyOrException.getOriginalPattern(), e);
- }
- }
-
- // Then, resolve the patterns.
+ Iterable<TargetPatternKey> targetPatternKeys =
+ TargetPatternValue.keys(targetPatterns, filteringPolicy);
Map<SkyKey, ValueOrException<TargetParsingException>> resolvedPatterns =
- env.getValuesOrThrow(patternKeys, TargetParsingException.class);
+ env.getValuesOrThrow(targetPatternKeys, TargetParsingException.class);
boolean valuesMissing = env.valuesMissing();
ImmutableList.Builder<Label> labels = valuesMissing ? null : new ImmutableList.Builder<>();
- for (TargetPatternValue.TargetPatternKey pattern : patternKeys) {
+ for (TargetPatternKey pattern : targetPatternKeys) {
TargetPatternValue value;
try {
value = (TargetPatternValue) resolvedPatterns.get(pattern).get();
@@ -96,8 +74,31 @@
return labels.build();
}
+ // TODO(bazel-team): look into moving this into SignedTargetPattern itself.
+ public static ImmutableList<SignedTargetPattern> parseAllSigned(
+ List<String> patterns, TargetPattern.Parser parser) throws InvalidTargetPatternException {
+ ImmutableList.Builder<SignedTargetPattern> parsedPatterns = ImmutableList.builder();
+ for (String pattern : patterns) {
+ try {
+ parsedPatterns.add(SignedTargetPattern.parse(pattern, parser));
+ } catch (TargetParsingException e) {
+ throw new InvalidTargetPatternException(pattern, e);
+ }
+ }
+ return parsedPatterns.build();
+ }
+
+ /** Converts patterns to signed patterns, considering all input patterns positive. */
+ public static ImmutableList<SignedTargetPattern> toSigned(List<TargetPattern> patterns) {
+ return patterns.stream()
+ .map(pattern -> SignedTargetPattern.create(pattern, Sign.POSITIVE))
+ .collect(toImmutableList());
+ }
+
/** Exception used when an error occurs in {@link #expandTargetPatterns}. */
- static final class InvalidTargetPatternException extends Exception {
+ // TODO(bazel-team): Consolidate this and TargetParsingException. Just have the latter store the
+ // original unparsed pattern too.
+ public static final class InvalidTargetPatternException extends Exception {
private String invalidPattern;
private TargetParsingException tpe;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java
index fecdf3d..5fecef1 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetPatternValue.java
@@ -13,15 +13,17 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.ResolvedTargets;
-import com.google.devtools.build.lib.cmdline.TargetParsingException;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern;
+import com.google.devtools.build.lib.cmdline.SignedTargetPattern.Sign;
import com.google.devtools.build.lib.cmdline.TargetPattern;
import com.google.devtools.build.lib.cmdline.TargetPattern.TargetsBelowDirectory;
import com.google.devtools.build.lib.cmdline.TargetPattern.TargetsBelowDirectory.ContainsResult;
@@ -102,55 +104,28 @@
}
/**
- * Create a target pattern {@link SkyKey}. Throws {@link TargetParsingException} if the provided
- * {@code pattern} cannot be parsed.
+ * Create a target pattern {@link SkyKey}.
*
- * @param pattern The pattern, eg "-foo/biz...". If the first character is "-", the pattern is
- * treated as a negative pattern.
+ * @param pattern The pattern, eg "-foo/biz...".
* @param policy The filtering policy, eg "only return test targets"
- * @param offset The offset to apply to relative target patterns.
*/
@ThreadSafe
- public static TargetPatternKey key(String pattern, FilteringPolicy policy, PathFragment offset)
- throws TargetParsingException {
- return Iterables.getOnlyElement(keys(ImmutableList.of(pattern), policy, offset)).getSkyKey();
+ public static TargetPatternKey key(SignedTargetPattern pattern, FilteringPolicy policy) {
+ return new TargetPatternKey(
+ pattern, pattern.sign() == Sign.POSITIVE ? policy : FilteringPolicies.NO_FILTER);
}
/**
- * Returns an iterable of {@link TargetPatternSkyKeyOrException}, with {@link TargetPatternKey}
- * arguments, in the same order as the list of patterns provided as input. If a provided pattern
- * fails to parse, the element in the returned iterable corresponding to it will throw when its
- * {@link TargetPatternSkyKeyOrException#getSkyKey} method is called.
+ * Returns an iterable of {@link TargetPatternKey}s, in the same order as the list of patterns
+ * provided as input.
*
- * @param patterns The list of patterns, eg "-foo/biz...". If a pattern's first character is "-",
- * it is treated as a negative pattern.
+ * @param patterns The list of patterns, eg "-foo/biz...".
* @param policy The filtering policy, eg "only return test targets"
- * @param offset The offset to apply to relative target patterns.
*/
@ThreadSafe
- public static Iterable<TargetPatternSkyKeyOrException> keys(
- List<String> patterns, FilteringPolicy policy, PathFragment offset) {
- TargetPattern.Parser parser = new TargetPattern.Parser(offset);
- ImmutableList.Builder<TargetPatternSkyKeyOrException> builder = ImmutableList.builder();
- for (String pattern : patterns) {
- boolean positive = !pattern.startsWith("-");
- String absoluteValueOfPattern = positive ? pattern : pattern.substring(1);
- TargetPattern targetPattern;
- try {
- targetPattern = parser.parse(absoluteValueOfPattern);
- } catch (TargetParsingException e) {
- builder.add(new TargetPatternSkyKeyException(e, absoluteValueOfPattern));
- continue;
- }
- TargetPatternKey targetPatternKey =
- new TargetPatternKey(
- targetPattern,
- positive ? policy : FilteringPolicies.NO_FILTER,
- /*isNegative=*/ !positive,
- offset);
- builder.add(new TargetPatternSkyKeyValue(targetPatternKey));
- }
- return builder.build();
+ public static Iterable<TargetPatternKey> keys(
+ List<SignedTargetPattern> patterns, FilteringPolicy policy) {
+ return patterns.stream().map(pattern -> key(pattern, policy)).collect(toImmutableList());
}
@ThreadSafe
@@ -189,12 +164,7 @@
policy =
FilteringPolicies.and(policy, new TargetExcludingFilteringPolicy(excludedSingleTargets));
}
- return new TargetPatternKey(
- original.getParsedPattern(),
- policy,
- original.isNegative(),
- original.getOffset(),
- excludedSubdirectories);
+ return new TargetPatternKey(original.getSignedParsedPattern(), policy, excludedSubdirectories);
}
private static class TargetPatternKeyWithExclusionsResult {
@@ -281,36 +251,26 @@
*/
@ThreadSafe
public static class TargetPatternKey implements SkyKey, Serializable {
- private final TargetPattern parsedPattern;
+ private final SignedTargetPattern signedParsedPattern;
private final FilteringPolicy policy;
- private final boolean isNegative;
- private final PathFragment offset;
/**
- * Must be "compatible" with {@link #parsedPattern}: if {@link #parsedPattern} is a {@link
- * TargetsBelowDirectory} object, then {@link TargetsBelowDirectory#containedIn} is false for
- * every element of {@code excludedSubdirectories}.
+ * Must be "compatible" with {@link #signedParsedPattern}: if {@link #signedParsedPattern} is a
+ * {@link TargetsBelowDirectory} object, then {@link TargetsBelowDirectory#containedIn} is false
+ * for every element of {@code excludedSubdirectories}.
*/
private final ImmutableSet<PathFragment> excludedSubdirectories;
- public TargetPatternKey(
- TargetPattern parsedPattern,
- FilteringPolicy policy,
- boolean isNegative,
- PathFragment offset) {
- this(parsedPattern, policy, isNegative, offset, ImmutableSet.of());
+ public TargetPatternKey(SignedTargetPattern signedParsedPattern, FilteringPolicy policy) {
+ this(signedParsedPattern, policy, ImmutableSet.of());
}
private TargetPatternKey(
- TargetPattern parsedPattern,
+ SignedTargetPattern signedParsedPattern,
FilteringPolicy policy,
- boolean isNegative,
- PathFragment offset,
ImmutableSet<PathFragment> excludedSubdirectories) {
- this.parsedPattern = Preconditions.checkNotNull(parsedPattern);
+ this.signedParsedPattern = Preconditions.checkNotNull(signedParsedPattern);
this.policy = Preconditions.checkNotNull(policy);
- this.isNegative = isNegative;
- this.offset = offset;
this.excludedSubdirectories = Preconditions.checkNotNull(excludedSubdirectories);
}
@@ -320,25 +280,25 @@
}
public String getPattern() {
- return parsedPattern.getOriginalPattern();
+ return signedParsedPattern.pattern().getOriginalPattern();
}
public TargetPattern getParsedPattern() {
- return parsedPattern;
+ return signedParsedPattern.pattern();
+ }
+
+ private SignedTargetPattern getSignedParsedPattern() {
+ return signedParsedPattern;
}
public boolean isNegative() {
- return isNegative;
+ return signedParsedPattern.sign() == Sign.NEGATIVE;
}
public FilteringPolicy getPolicy() {
return policy;
}
- public PathFragment getOffset() {
- return offset;
- }
-
public ImmutableSet<PathFragment> getExcludedSubdirectories() {
return excludedSubdirectories;
}
@@ -347,15 +307,14 @@
public String toString() {
return String.format(
"%s, excludedSubdirs=%s, filteringPolicy=%s",
- (isNegative ? "-" : "") + parsedPattern.getOriginalPattern(),
+ (isNegative() ? "-" : "") + signedParsedPattern.pattern().getOriginalPattern(),
excludedSubdirectories,
getPolicy());
}
@Override
public int hashCode() {
- return Objects.hash(parsedPattern, isNegative, policy, offset,
- excludedSubdirectories);
+ return Objects.hash(signedParsedPattern, policy, excludedSubdirectories);
}
@Override
@@ -365,69 +324,9 @@
}
TargetPatternKey other = (TargetPatternKey) obj;
- return other.isNegative == this.isNegative && other.parsedPattern.equals(this.parsedPattern)
- && other.offset.equals(this.offset) && other.policy.equals(this.policy)
+ return other.signedParsedPattern.equals(this.signedParsedPattern)
+ && other.policy.equals(this.policy)
&& other.excludedSubdirectories.equals(this.excludedSubdirectories);
}
}
-
- /**
- * Wrapper for a target pattern {@link SkyKey} or the {@link TargetParsingException} thrown when
- * trying to compute it.
- */
- public interface TargetPatternSkyKeyOrException {
-
- /**
- * Returns the stored {@link SkyKey} or throws {@link TargetParsingException} if one was thrown
- * when computing the key.
- */
- TargetPatternKey getSkyKey() throws TargetParsingException;
-
- /**
- * Returns the pattern that resulted in the stored {@link SkyKey} or {@link
- * TargetParsingException}.
- */
- String getOriginalPattern();
- }
-
- private static final class TargetPatternSkyKeyValue implements TargetPatternSkyKeyOrException {
-
- private final TargetPatternKey value;
-
- private TargetPatternSkyKeyValue(TargetPatternKey value) {
- this.value = value;
- }
-
- @Override
- public TargetPatternKey getSkyKey() throws TargetParsingException {
- return value;
- }
-
- @Override
- public String getOriginalPattern() {
- return ((TargetPatternKey) value.argument()).getPattern();
- }
- }
-
- private static final class TargetPatternSkyKeyException implements
- TargetPatternSkyKeyOrException {
-
- private final TargetParsingException exception;
- private final String originalPattern;
-
- private TargetPatternSkyKeyException(TargetParsingException exception, String originalPattern) {
- this.exception = exception;
- this.originalPattern = originalPattern;
- }
-
- @Override
- public TargetPatternKey getSkyKey() throws TargetParsingException {
- throw exception;
- }
-
- @Override
- public String getOriginalPattern() {
- return originalPattern;
- }
- }
}