Home | History | Annotate | Download | only in options
      1 // Copyright 2017 The Bazel Authors. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package com.google.devtools.common.options;
     16 
     17 import com.google.common.collect.ImmutableList;
     18 import java.util.function.Function;
     19 import javax.annotation.Nullable;
     20 
     21 /**
     22  * The representation of a parsed option instance.
     23  *
     24  * <p>An option instance is distinct from the final value of an option, as multiple instances
     25  * provide values may be overridden or combined in some way.
     26  */
     27 public final class ParsedOptionDescription {
     28 
     29   private final OptionDefinition optionDefinition;
     30   private final String commandLineForm;
     31   @Nullable private final String unconvertedValue;
     32   private final OptionInstanceOrigin origin;
     33 
     34   public ParsedOptionDescription(
     35       OptionDefinition optionDefinition,
     36       String commandLineForm,
     37       @Nullable String unconvertedValue,
     38       OptionInstanceOrigin origin) {
     39     this.optionDefinition = optionDefinition;
     40     this.commandLineForm = commandLineForm;
     41     this.unconvertedValue = unconvertedValue;
     42     this.origin = origin;
     43   }
     44 
     45   public OptionDefinition getOptionDefinition() {
     46     return optionDefinition;
     47   }
     48 
     49   public String getCommandLineForm() {
     50     return commandLineForm;
     51   }
     52 
     53   public String getCanonicalForm() {
     54     return getCanonicalFormWithValueEscaper(s -> s);
     55   }
     56 
     57   public String getCanonicalFormWithValueEscaper(Function<String, String> escapingFunction) {
     58     // For boolean flags (note that here we do not check for TriState flags, only flags with actual
     59     // boolean values, so that we know the return type of getConvertedValue), use the --[no]flag
     60     // form for the canonical value.
     61     if (optionDefinition.getType().equals(boolean.class)) {
     62       try {
     63         return ((boolean) getConvertedValue() ? "--" : "--no") + optionDefinition.getOptionName();
     64       } catch (OptionsParsingException e) {
     65         throw new RuntimeException("Unexpected parsing exception", e);
     66       }
     67     } else {
     68       String optionString = "--" + optionDefinition.getOptionName();
     69       if (unconvertedValue != null) { // Can be null for Void options.
     70         optionString += "=" + escapingFunction.apply(unconvertedValue);
     71       }
     72       return optionString;
     73     }
     74   }
     75 
     76   @Deprecated
     77   // TODO(b/65646296) Once external dependencies are cleaned up, use getCanonicalForm()
     78   String getDeprecatedCanonicalForm() {
     79     String value = unconvertedValue;
     80     // For boolean flags (note that here we do not check for TriState flags, only flags with actual
     81     // boolean values, so that we know the return type of getConvertedValue), set them all to 1 or
     82     // 0, instead of keeping the wide variety of values we accept in their original form.
     83     if (optionDefinition.getType().equals(boolean.class)) {
     84       try {
     85         value = (boolean) getConvertedValue() ? "1" : "0";
     86       } catch (OptionsParsingException e) {
     87         throw new RuntimeException("Unexpected parsing exception", e);
     88       }
     89     }
     90     return String.format("--%s=%s", optionDefinition.getOptionName(), value);
     91   }
     92 
     93   public boolean isBooleanOption() {
     94     return optionDefinition.getType().equals(boolean.class);
     95   }
     96 
     97   private OptionDocumentationCategory documentationCategory() {
     98     return optionDefinition.getDocumentationCategory();
     99   }
    100 
    101   private ImmutableList<OptionMetadataTag> metadataTags() {
    102     return ImmutableList.copyOf(optionDefinition.getOptionMetadataTags());
    103   }
    104 
    105   public boolean isDocumented() {
    106     return documentationCategory() != OptionDocumentationCategory.UNDOCUMENTED && !isHidden();
    107   }
    108 
    109   public boolean isHidden() {
    110     ImmutableList<OptionMetadataTag> tags = metadataTags();
    111     return tags.contains(OptionMetadataTag.HIDDEN) || tags.contains(OptionMetadataTag.INTERNAL);
    112   }
    113 
    114   public String getUnconvertedValue() {
    115     return unconvertedValue;
    116   }
    117 
    118   public OptionInstanceOrigin getOrigin() {
    119     return origin;
    120   }
    121 
    122   public OptionPriority getPriority() {
    123     return origin.getPriority();
    124   }
    125 
    126   public String getSource() {
    127     return origin.getSource();
    128   }
    129 
    130   OptionDefinition getImplicitDependent() {
    131     return origin.getImplicitDependent();
    132   }
    133 
    134   OptionDefinition getExpandedFrom() {
    135     return origin.getExpandedFrom();
    136   }
    137 
    138   public boolean isExplicit() {
    139     return origin.getExpandedFrom() == null && origin.getImplicitDependent() == null;
    140   }
    141 
    142   public Object getConvertedValue() throws OptionsParsingException {
    143     Converter<?> converter = optionDefinition.getConverter();
    144     try {
    145       return converter.convert(unconvertedValue);
    146     } catch (OptionsParsingException e) {
    147       // The converter doesn't know the option name, so we supply it here by re-throwing:
    148       throw new OptionsParsingException(
    149           String.format("While parsing option %s: %s", commandLineForm, e.getMessage()), e);
    150     }
    151   }
    152 
    153   @Override
    154   public String toString() {
    155     StringBuilder result = new StringBuilder();
    156     result.append(optionDefinition);
    157     result.append("set to '").append(unconvertedValue).append("' ");
    158     result.append("with priority ").append(origin.getPriority());
    159     if (origin.getSource() != null) {
    160       result.append(" and source '").append(origin.getSource()).append("'");
    161     }
    162     return result.toString();
    163   }
    164 
    165 }
    166