diff options
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.java | 150 |
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); + } + } +} |