aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/query2/engine
diff options
context:
space:
mode:
authorGravatar Liam Miller-Cushon <cushon@google.com>2015-04-10 00:37:55 +0000
committerGravatar Ulf Adams <ulfjack@google.com>2015-04-10 08:04:04 +0000
commitcc44636d2d538bc91e7291ed4607f2bdce356827 (patch)
tree6005a011781327692ee88fe090a4967da0a48385 /src/main/java/com/google/devtools/build/lib/query2/engine
parentf7cf477913ae9c14f77a2d0d689b4207e3d51c37 (diff)
Add a visibility predicate to blaze query.
The visible(x, y) query expression computes the subset of nodes in y visible from all nodes in x. RELNOTES: Add a visibility predicate to blaze query. -- MOS_MIGRATED_REVID=90765071
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/query2/engine')
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/engine/QueryVisibility.java117
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/engine/VisibleFunction.java95
3 files changed, 225 insertions, 1 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
index 46a7afd42d..1a7d8d844d 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
@@ -271,6 +271,11 @@ public interface QueryEnvironment<T> {
String getLabel(T target);
/**
+ * Returns the label of the target's package as a string, e.g. {@code //some/package}
+ */
+ String getPackage(T target);
+
+ /**
* Returns whether the given target is a rule.
*/
boolean isRule(T target);
@@ -331,6 +336,12 @@ public interface QueryEnvironment<T> {
* @throws IllegalArgumentException if target is not a rule (according to {@link #isRule})
*/
Iterable<String> getAttrAsString(T target, String attrName);
+
+ /**
+ * Returns the set of package specifications the given target is visible from, represented as
+ * {@link QueryVisibility}s.
+ */
+ Set<QueryVisibility<T>> getVisibility(T from) throws QueryException;
}
/** List of the default query functions. */
@@ -346,6 +357,7 @@ public interface QueryEnvironment<T> {
new SomePathFunction(),
new TestsFunction(),
new DepsFunction(),
- new RdepsFunction()
+ new RdepsFunction(),
+ new VisibleFunction()
);
}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryVisibility.java b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryVisibility.java
new file mode 100644
index 0000000000..92a5200320
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryVisibility.java
@@ -0,0 +1,117 @@
+// Copyright 2015 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.query2.engine;
+
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
+
+/**
+ * A predicate for targets included in the visibility list of a rule.
+ *
+ * <p>A rule's visibility is described by a set of {@link QueryVisibility}. Each element
+ * in the set corresponds to an entry in the rule's visibility attribute, or an entry in the
+ * packages attribute of an included package_group.
+ */
+public abstract class QueryVisibility<T> {
+
+ /** Returns true if the visibility specification includes the given target's package. */
+ public abstract boolean contains(T target);
+
+ /** Global visibility. */
+ @SuppressWarnings("unchecked") // Safe covariant cast.
+ public static <T> QueryVisibility<T> everything() {
+ return (QueryVisibility<T>) (Object) EVERYTHING;
+ }
+
+ private static final QueryVisibility<?> EVERYTHING = new QueryVisibility<Object>() {
+ @Override
+ public boolean contains(Object target) {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "QueryVisibility(//visibility:public)";
+ }
+ };
+
+ /**
+ * Empty visibility.
+ *
+ * <p>This is useful as a sentinel to indicate that a package specification could be parsed into
+ * a {@link QueryVisibility}. Same-package visibility is handled separately by
+ * {@link VisibleFunction}.
+ */
+ @SuppressWarnings("unchecked") // Safe covariant cast.
+ public static <T> QueryVisibility<T> nothing() {
+ return (QueryVisibility<T>) (Object) NOTHING;
+ }
+
+ private static final QueryVisibility<?> NOTHING = new QueryVisibility<Object>() {
+ @Override
+ public boolean contains(Object target) {
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "QueryVisibility(//visibility:private)";
+ }
+ };
+
+ /**
+ * Same-package visibility.
+ *
+ * <p>Targets are always visible to other targets in the same package. Additionally, targets
+ * under java/ are always visible to the corresponding package in javatests/.
+ */
+ public static <T> QueryVisibility<T> samePackage(T from, TargetAccessor<T> accessor) {
+ return new SamePackageVisibility<>(from, accessor);
+ }
+
+ private static final class SamePackageVisibility<T> extends QueryVisibility<T> {
+
+ private static final String JAVA_PREFIX = "java/";
+ private static final String JAVATESTS_PREFIX = "javatests/";
+
+ private final String packageName;
+ private final TargetAccessor<T> accessor;
+
+ public SamePackageVisibility(T target, TargetAccessor<T> accessor) {
+ this.packageName = accessor.getPackage(target);
+ this.accessor = accessor;
+ }
+
+ @Override
+ public boolean contains(T target) {
+ String other = accessor.getPackage(target);
+ if (packageName.equals(other)) {
+ return true;
+ }
+
+ // packages in java/ are always visible from the corresponding package in javatests/
+ if (other.startsWith(JAVATESTS_PREFIX)
+ && packageName.equals(JAVA_PREFIX + other.substring(JAVATESTS_PREFIX.length()))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("QueryVisibility(samePackage=%s)", "<PACKAGE>");
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/VisibleFunction.java b/src/main/java/com/google/devtools/build/lib/query2/engine/VisibleFunction.java
new file mode 100644
index 0000000000..f268116805
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/VisibleFunction.java
@@ -0,0 +1,95 @@
+// Copyright 2015 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.query2.engine;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Argument;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.ArgumentType;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A visible(x, y) query expression, which computes the subset of nodes in y
+ * that are visible from all nodes in x.
+ *
+ * <pre>expr ::= VISIBILE '(' expr ',' expr ')'</pre>
+ *
+ * <p>Example: return targets from the package //bar/baz that are visible to //foo.
+ *
+ * <pre>
+ * visible(//foo, //bar/baz:*)
+ * </pre>
+ */
+public class VisibleFunction implements QueryFunction {
+
+ @Override
+ public String getName() {
+ return "visible";
+ }
+
+ @Override
+ public int getMandatoryArguments() {
+ return 2;
+ }
+
+ @Override
+ public List<ArgumentType> getArgumentTypes() {
+ return ImmutableList.of(ArgumentType.EXPRESSION, ArgumentType.EXPRESSION);
+ }
+
+ @Override
+ public <T> Set<T> eval(QueryEnvironment<T> env, QueryExpression expression, List<Argument> args)
+ throws QueryException {
+ Set<T> toSet = args.get(0).getExpression().eval(env);
+ Set<T> targets = args.get(1).getExpression().eval(env);
+
+ ImmutableSet.Builder<T> visible = ImmutableSet.builder();
+ for (T target : targets) {
+ if (visibleToAll(env, toSet, target)) {
+ visible.add(target);
+ }
+ }
+ return visible.build();
+ }
+
+ /**
+ * Returns true if {@code target} is visible to all targets in {@code toSet}.
+ */
+ private <T> boolean visibleToAll(
+ QueryEnvironment<T> env, Set<T> toSet, T target) throws QueryException {
+ for (T to : toSet) {
+ if (!visible(env, to, target)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the target {@code from} is visible to the target {@code to}.
+ */
+ public <T> boolean visible(QueryEnvironment<T> env, T to, T from) throws QueryException {
+ Set<QueryVisibility<T>> visiblePackages = env.getAccessor().getVisibility(from);
+ for (QueryVisibility<T> spec : visiblePackages) {
+ if (spec.contains(to)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}