// 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.Label; import com.google.devtools.build.lib.cmdline.LabelValidator; 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. * *

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. * *

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 + "/..."; } } /** * Exception class to be thrown when a specification cannot be parsed. */ public static class InvalidPackageSpecificationException extends Exception { public InvalidPackageSpecificationException(String message) { super(message); } } }