aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/packages/PackageSpecification.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/packages/PackageSpecification.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/PackageSpecification.java150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageSpecification.java b/src/main/java/com/google/devtools/build/lib/packages/PackageSpecification.java
new file mode 100644
index 0000000000..20524aa411
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageSpecification.java
@@ -0,0 +1,150 @@
+// 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.packages;
+
+import com.google.devtools.build.lib.cmdline.LabelValidator;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * A class that represents some packages that are included in the visibility list of a rule.
+ */
+public abstract class PackageSpecification {
+ private static final String PACKAGE_LABEL = "__pkg__";
+ private static final String SUBTREE_LABEL = "__subpackages__";
+ private static final String ALL_BENEATH_SUFFIX = "/...";
+ public static final PackageSpecification EVERYTHING =
+ new AllPackagesBeneath(new PathFragment(""));
+
+ public abstract boolean containsPackage(PathFragment packageName);
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+
+ if (!(that instanceof PackageSpecification)) {
+ return false;
+ }
+
+ return this.toString().equals(that.toString());
+ }
+
+ /**
+ * Parses a string as a visibility specification.
+ * Throws {@link InvalidPackageSpecificationException} if the label cannot be parsed.
+ *
+ * <p>Note that these strings are different from what {@link #fromLabel} understands.
+ */
+ public static PackageSpecification fromString(final String spec)
+ throws InvalidPackageSpecificationException {
+ String result = spec;
+ boolean allBeneath = false;
+
+ if (result.startsWith("//")) {
+ result = spec.substring(2);
+ } else {
+ throw new InvalidPackageSpecificationException("invalid package label: " + spec);
+ }
+
+ if (result.indexOf(':') >= 0) {
+ throw new InvalidPackageSpecificationException("invalid package label: " + spec);
+ }
+
+ if (result.equals("...")) {
+ // Special case: //... will not end in /...
+ return EVERYTHING;
+ }
+
+ if (result.endsWith(ALL_BENEATH_SUFFIX)) {
+ allBeneath = true;
+ result = result.substring(0, result.length() - ALL_BENEATH_SUFFIX.length());
+ }
+
+ String errorMessage = LabelValidator.validatePackageName(result);
+ if (errorMessage == null) {
+ return allBeneath ?
+ new AllPackagesBeneath(new PathFragment(result)) :
+ new SinglePackage(new PathFragment(result));
+ } else {
+ throw new InvalidPackageSpecificationException(errorMessage);
+ }
+ }
+
+ /**
+ * Parses a label as a visibility specification. returns null if the label cannot be parsed.
+ *
+ * <p>Note that these strings are different from what {@link #fromString} understands.
+ */
+ public static PackageSpecification fromLabel(Label label) {
+ if (label.getName().equals(PACKAGE_LABEL)) {
+ return new SinglePackage(label.getPackageFragment());
+ } else if (label.getName().equals(SUBTREE_LABEL)) {
+ return new AllPackagesBeneath(label.getPackageFragment());
+ } else {
+ return null;
+ }
+ }
+
+ private static class SinglePackage extends PackageSpecification {
+ private PathFragment singlePackageName;
+
+ public SinglePackage(PathFragment packageName) {
+ this.singlePackageName = packageName;
+ }
+
+ @Override
+ public boolean containsPackage(PathFragment packageName) {
+ return this.singlePackageName.equals(packageName);
+ }
+
+ @Override
+ public String toString() {
+ return singlePackageName.toString();
+ }
+ }
+
+ private static class AllPackagesBeneath extends PackageSpecification {
+ private PathFragment prefix;
+
+ public AllPackagesBeneath(PathFragment prefix) {
+ this.prefix = prefix;
+ }
+
+ @Override
+ public boolean containsPackage(PathFragment packageName) {
+ return packageName.startsWith(prefix);
+ }
+
+ @Override
+ public String toString() {
+ return prefix.equals(new PathFragment("")) ? "..." : prefix.toString() + "/...";
+ }
+ }
+
+ /**
+ * Exception class to be thrown when a specification cannot be parsed.
+ */
+ public static class InvalidPackageSpecificationException extends Exception {
+ public InvalidPackageSpecificationException(String message) {
+ super(message);
+ }
+ }
+}