18c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// Copyright 2017 The Bazel Authors. All rights reserved. 28c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// 38c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// Licensed under the Apache License, Version 2.0 (the "License"); 48c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// you may not use this file except in compliance with the License. 58c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// You may obtain a copy of the License at 68c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// 78c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// http://www.apache.org/licenses/LICENSE-2.0 88c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// 98c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// Unless required by applicable law or agreed to in writing, software 108c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// distributed under the License is distributed on an "AS IS" BASIS, 118c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// See the License for the specific language governing permissions and 138c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin// limitations under the License. 148c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 158c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarinpackage com.google.devtools.common.options; 168c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 178c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarinimport com.google.common.collect.ImmutableList; 18a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarinimport java.util.function.Function; 198c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarinimport javax.annotation.Nullable; 208c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 218c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin/** 2205bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin * The representation of a parsed option instance. 238c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin * 2405bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin * <p>An option instance is distinct from the final value of an option, as multiple instances 2505bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin * provide values may be overridden or combined in some way. 268c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin */ 27cff0d218a8d061b3568a6197b8d456424d9c9c4accalvarinpublic final class ParsedOptionDescription { 2805bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin 298c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin private final OptionDefinition optionDefinition; 30be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin private final String commandLineForm; 31bf096ba935f132b5da0ad941f41897f7a7409fb3ccalvarin @Nullable private final String unconvertedValue; 3205bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin private final OptionInstanceOrigin origin; 338c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 34cff0d218a8d061b3568a6197b8d456424d9c9c4accalvarin public ParsedOptionDescription( 358c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin OptionDefinition optionDefinition, 36be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin String commandLineForm, 37bf096ba935f132b5da0ad941f41897f7a7409fb3ccalvarin @Nullable String unconvertedValue, 3805bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin OptionInstanceOrigin origin) { 398c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin this.optionDefinition = optionDefinition; 40be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin this.commandLineForm = commandLineForm; 41bf096ba935f132b5da0ad941f41897f7a7409fb3ccalvarin this.unconvertedValue = unconvertedValue; 4205bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin this.origin = origin; 438c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 448c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 45bf096ba935f132b5da0ad941f41897f7a7409fb3ccalvarin public OptionDefinition getOptionDefinition() { 468c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin return optionDefinition; 478c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 488c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 49be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin public String getCommandLineForm() { 50be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin return commandLineForm; 51be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin } 52be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin 53a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin public String getCanonicalForm() { 54a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin return getCanonicalFormWithValueEscaper(s -> s); 55a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 56a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin 57a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin public String getCanonicalFormWithValueEscaper(Function<String, String> escapingFunction) { 58a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin // For boolean flags (note that here we do not check for TriState flags, only flags with actual 59a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin // boolean values, so that we know the return type of getConvertedValue), use the --[no]flag 60a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin // form for the canonical value. 61a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin if (optionDefinition.getType().equals(boolean.class)) { 62a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin try { 63a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin return ((boolean) getConvertedValue() ? "--" : "--no") + optionDefinition.getOptionName(); 64a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } catch (OptionsParsingException e) { 65a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin throw new RuntimeException("Unexpected parsing exception", e); 66a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 67a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } else { 68a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin String optionString = "--" + optionDefinition.getOptionName(); 69a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin if (unconvertedValue != null) { // Can be null for Void options. 70a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin optionString += "=" + escapingFunction.apply(unconvertedValue); 71a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 72a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin return optionString; 73a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 74a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 75a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin 76a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin @Deprecated 77a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin // TODO(b/65646296) Once external dependencies are cleaned up, use getCanonicalForm() 78a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin String getDeprecatedCanonicalForm() { 79a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin String value = unconvertedValue; 80a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin // For boolean flags (note that here we do not check for TriState flags, only flags with actual 81a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin // boolean values, so that we know the return type of getConvertedValue), set them all to 1 or 82a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin // 0, instead of keeping the wide variety of values we accept in their original form. 83a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin if (optionDefinition.getType().equals(boolean.class)) { 84a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin try { 85a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin value = (boolean) getConvertedValue() ? "1" : "0"; 86a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } catch (OptionsParsingException e) { 87a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin throw new RuntimeException("Unexpected parsing exception", e); 88a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 89a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 90a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin return String.format("--%s=%s", optionDefinition.getOptionName(), value); 91a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin } 92a0d433e79adbd70bc30ee613654fdf3fbb9de991ccalvarin 938c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin public boolean isBooleanOption() { 948c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin return optionDefinition.getType().equals(boolean.class); 958c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 968c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 978c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin private OptionDocumentationCategory documentationCategory() { 988c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin return optionDefinition.getDocumentationCategory(); 998c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1008c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 1018c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin private ImmutableList<OptionMetadataTag> metadataTags() { 1028c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin return ImmutableList.copyOf(optionDefinition.getOptionMetadataTags()); 1038c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1048c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 1058c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin public boolean isDocumented() { 1068c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin return documentationCategory() != OptionDocumentationCategory.UNDOCUMENTED && !isHidden(); 1078c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1088c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 1098c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin public boolean isHidden() { 1108c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin ImmutableList<OptionMetadataTag> tags = metadataTags(); 1118c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin return tags.contains(OptionMetadataTag.HIDDEN) || tags.contains(OptionMetadataTag.INTERNAL); 1128c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1138c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 114bf096ba935f132b5da0ad941f41897f7a7409fb3ccalvarin public String getUnconvertedValue() { 115bf096ba935f132b5da0ad941f41897f7a7409fb3ccalvarin return unconvertedValue; 1168c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1178c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 118195dd40824457bb0b3b934ec2c14ab36840f1ff0ccalvarin public OptionInstanceOrigin getOrigin() { 119195dd40824457bb0b3b934ec2c14ab36840f1ff0ccalvarin return origin; 120195dd40824457bb0b3b934ec2c14ab36840f1ff0ccalvarin } 121195dd40824457bb0b3b934ec2c14ab36840f1ff0ccalvarin 1222c2f636ed26b6cf80d2135f0d337e159e047e89dccalvarin public OptionPriority getPriority() { 12305bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin return origin.getPriority(); 1248c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1258c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 1268c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin public String getSource() { 12705bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin return origin.getSource(); 12805bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin } 12905bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin 13005bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin OptionDefinition getImplicitDependent() { 13105bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin return origin.getImplicitDependent(); 13205bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin } 13305bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin 13405bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin OptionDefinition getExpandedFrom() { 13505bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin return origin.getExpandedFrom(); 1368c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1378c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 1388c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin public boolean isExplicit() { 13905bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin return origin.getExpandedFrom() == null && origin.getImplicitDependent() == null; 1408c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1418c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin 142be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin public Object getConvertedValue() throws OptionsParsingException { 143be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin Converter<?> converter = optionDefinition.getConverter(); 144be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin try { 145be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin return converter.convert(unconvertedValue); 146be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin } catch (OptionsParsingException e) { 147be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin // The converter doesn't know the option name, so we supply it here by re-throwing: 148be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin throw new OptionsParsingException( 149be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin String.format("While parsing option %s: %s", commandLineForm, e.getMessage()), e); 150be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin } 151be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin } 152be286cfc3497bf329a5224f56b3e2d6a451c243dccalvarin 1538c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin @Override 1548c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin public String toString() { 1558c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin StringBuilder result = new StringBuilder(); 156195dd40824457bb0b3b934ec2c14ab36840f1ff0ccalvarin result.append(optionDefinition); 157bf096ba935f132b5da0ad941f41897f7a7409fb3ccalvarin result.append("set to '").append(unconvertedValue).append("' "); 15805bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin result.append("with priority ").append(origin.getPriority()); 15905bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin if (origin.getSource() != null) { 16005bb5c28c6be8320c06d8bb1bafd0be586678138ccalvarin result.append(" and source '").append(origin.getSource()).append("'"); 1618c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1628c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin return result.toString(); 1638c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin } 1642c366b859ba2c84184e38450786e33368c9c39c2ccalvarin 1658c3292b0ae37edbbc3470d3a3ad34fffd2aef413ccalvarin} 166