// Copyright 2014 The Bazel Authors. 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.util.StringUtil; import com.google.devtools.common.options.Converter; import com.google.devtools.common.options.OptionsParsingException; import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.Set; /** * Converter that translates a string of the form "value1,value2,-value3,value4" * into a corresponding set of allowed Enum values. * * <p>Values preceded by '-' are excluded from this set. So "value1,-value2,value3" * translates to the set [EnumType.value1, EnumType.value3]. * * <p>If *all* values are exclusions (e.g. "-value1,-value2,-value3"), the returned * set contains all values for the Enum type *except* those specified. */ class EnumFilterConverter<E extends Enum<E>> implements Converter<Set<E>> { private final Set<String> allowedValues = new LinkedHashSet<>(); private final Class<E> typeClass; private final String prettyEnumName; /** * Constructor. * * @param typeClass this should be E.class (Java generics can't infer that directly) * @param userFriendlyName a user-friendly description of this enum type */ public EnumFilterConverter(Class<E> typeClass, String userFriendlyName) { this.typeClass = typeClass; this.prettyEnumName = userFriendlyName; for (E value : EnumSet.allOf(typeClass)) { allowedValues.add(value.name()); } } /** * Returns the set of allowed values for the option. * * Implements {@link #convert(String)}. */ @Override public Set<E> convert(String input) throws OptionsParsingException { if (input.isEmpty()) { return Collections.emptySet(); } EnumSet<E> includedSet = EnumSet.noneOf(typeClass); EnumSet<E> excludedSet = EnumSet.noneOf(typeClass); for (String value : input.split(",", -1)) { boolean excludeFlag = value.startsWith("-"); String s = (excludeFlag ? value.substring(1) : value).toUpperCase(); if (!allowedValues.contains(s)) { throw new OptionsParsingException("Invalid " + prettyEnumName + " filter '" + value + "' in the input '" + input + "'"); } (excludeFlag ? excludedSet : includedSet).add(Enum.valueOf(typeClass, s)); } if (includedSet.isEmpty()) { includedSet = EnumSet.complementOf(excludedSet); } else { includedSet.removeAll(excludedSet); } if (includedSet.isEmpty()) { throw new OptionsParsingException( Character.toUpperCase(prettyEnumName.charAt(0)) + prettyEnumName.substring(1) + " filter '" + input + "' definition cannot match any tests"); } return includedSet; } /** * Implements {@link #getTypeDescription()}. */ @Override public final String getTypeDescription() { return "comma-separated list of values: " + StringUtil.joinEnglishList(allowedValues).toLowerCase(); } }