aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java
new file mode 100644
index 0000000000..3f9f22f61c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetMarkerFunction.java
@@ -0,0 +1,134 @@
+// Copyright 2014 Google Inc. 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.skyframe;
+
+import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.NoSuchTargetException;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.packages.PackageIdentifier;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.syntax.Label;
+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.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+/**
+ * A SkyFunction for {@link TargetMarkerValue}s.
+ */
+public final class TargetMarkerFunction implements SkyFunction {
+
+ public TargetMarkerFunction() {
+ }
+
+ @Override
+ public SkyValue compute(SkyKey key, Environment env) throws TargetMarkerFunctionException {
+ Label label = (Label) key.argument();
+ PathFragment pkgForLabel = label.getPackageFragment();
+
+ if (label.getName().contains("/")) {
+ // This target is in a subdirectory, therefore it could potentially be invalidated by
+ // a new BUILD file appearing in the hierarchy.
+ PathFragment containingDirectory = label.toPathFragment().getParentDirectory();
+ ContainingPackageLookupValue containingPackageLookupValue = null;
+ try {
+ PackageIdentifier newPkgId = new PackageIdentifier(
+ label.getPackageIdentifier().getRepository(), containingDirectory);
+ containingPackageLookupValue = (ContainingPackageLookupValue) env.getValueOrThrow(
+ ContainingPackageLookupValue.key(newPkgId),
+ BuildFileNotFoundException.class, InconsistentFilesystemException.class);
+ } catch (BuildFileNotFoundException e) {
+ // Thrown when there are IO errors looking for BUILD files.
+ throw new TargetMarkerFunctionException(e);
+ } catch (InconsistentFilesystemException e) {
+ throw new TargetMarkerFunctionException(new NoSuchTargetException(label,
+ e.getMessage()));
+ }
+ if (containingPackageLookupValue == null) {
+ return null;
+ }
+ if (!containingPackageLookupValue.hasContainingPackage()) {
+ // This means the label's package doesn't exist. E.g. there is no package 'a' and we are
+ // trying to build the target for label 'a:b/foo'.
+ throw new TargetMarkerFunctionException(new BuildFileNotFoundException(
+ pkgForLabel.getPathString(), "BUILD file not found on package path for '"
+ + pkgForLabel.getPathString() + "'"));
+ }
+ if (!containingPackageLookupValue.getContainingPackageName().equals(
+ label.getPackageIdentifier())) {
+ throw new TargetMarkerFunctionException(new NoSuchTargetException(label,
+ String.format("Label '%s' crosses boundary of subpackage '%s'", label,
+ containingPackageLookupValue.getContainingPackageName())));
+ }
+ }
+
+ SkyKey pkgSkyKey = PackageValue.key(label.getPackageIdentifier());
+ NoSuchPackageException nspe = null;
+ Package pkg;
+ try {
+ PackageValue value = (PackageValue)
+ env.getValueOrThrow(pkgSkyKey, NoSuchPackageException.class);
+ if (value == null) {
+ return null;
+ }
+ pkg = value.getPackage();
+ } catch (NoSuchPackageException e) {
+ // For consistency with pre-Skyframe Blaze, we can return a valid Target from a Package
+ // containing errors.
+ pkg = e.getPackage();
+ if (pkg == null) {
+ // Re-throw this exception with our key because root causes should be targets, not packages.
+ throw new TargetMarkerFunctionException(e);
+ }
+ nspe = e;
+ }
+
+ Target target;
+ try {
+ target = pkg.getTarget(label.getName());
+ } catch (NoSuchTargetException e) {
+ throw new TargetMarkerFunctionException(e);
+ }
+
+ if (nspe != null) {
+ // There is a target, but its package is in error. We rethrow so that the root cause is the
+ // target, not the package. Note that targets are only in error when their package is
+ // "in error" (because a package is in error if there was an error evaluating the package, or
+ // if one of its targets was in error).
+ throw new TargetMarkerFunctionException(new NoSuchTargetException(target, nspe));
+ }
+ return TargetMarkerValue.TARGET_MARKER_INSTANCE;
+ }
+
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return Label.print((Label) skyKey.argument());
+ }
+
+ /**
+ * Used to declare all the exception types that can be wrapped in the exception thrown by
+ * {@link TargetMarkerFunction#compute}.
+ */
+ private static final class TargetMarkerFunctionException extends SkyFunctionException {
+ public TargetMarkerFunctionException(NoSuchTargetException e) {
+ super(e, Transience.PERSISTENT);
+ }
+
+ public TargetMarkerFunctionException(NoSuchPackageException e) {
+ super(e, Transience.PERSISTENT);
+ }
+ }
+}