1 // Copyright 2014 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 package com.google.devtools.common.options;
15 
16 import java.util.Objects;
17 
18 /**
19  * The position of an option in the interpretation order. Options are interpreted using a
20  * last-option-wins system for single valued options, and are listed in that order for
21  * multiple-valued options.
22  *
23  * <p>The position of the option is in category order, and within the priority category in index
24  * order.
25  */
26 public class OptionPriority implements Comparable<OptionPriority> {
27   private final PriorityCategory priorityCategory;
28   private final int index;
29   private final boolean locked;
30 
31   private OptionPriority(PriorityCategory priorityCategory, int index, boolean locked) {
32     this.priorityCategory = priorityCategory;
33     this.index = index;
34     this.locked = locked;
35   }
36 
37   /** Get the first OptionPriority for that category. */
38   static OptionPriority lowestOptionPriorityAtCategory(PriorityCategory category) {
39     return new OptionPriority(category, 0, false);
40   }
41 
42   /**
43    * Get the priority for the option following this one. In normal, incremental option parsing, the
44    * returned priority would compareTo as after the current one. Does not increment locked
45    * priorities.
46    */
47   static OptionPriority nextOptionPriority(OptionPriority priority) {
48     if (priority.locked) {
49       return priority;
50     }
51     return new OptionPriority(priority.priorityCategory, priority.index + 1, false);
52   }
53 
54   /**
55    * Return a priority for this option that will avoid priority increases by calls to
56    * nextOptionPriority.
57    *
58    * <p>Some options are expanded in-place, and need to be all parsed at the priority of the
59    * original option. In this case, parsing one of these after another should not cause the option
60    * to be considered as higher priority than the ones before it (this would cause overlap between
61    * the expansion of --expansion_flag and a option following it in the same list of options).
62    */
63   public static OptionPriority getLockedPriority(OptionPriority priority) {
64     return new OptionPriority(priority.priorityCategory, priority.index, true);
65   }
66 
67   public PriorityCategory getPriorityCategory() {
68     return priorityCategory;
69   }
70 
71   @Override
72   public int compareTo(OptionPriority o) {
73     if (priorityCategory.equals(o.priorityCategory)) {
74       return index - o.index;
75     }
76     return priorityCategory.ordinal() - o.priorityCategory.ordinal();
77   }
78 
79   @Override
80   public boolean equals(Object o) {
81     if (o instanceof OptionPriority) {
82       OptionPriority other = (OptionPriority) o;
83       return other.priorityCategory.equals(priorityCategory) && other.index == index;
84     }
85     return false;
86   }
87 
88   @Override
89   public int hashCode() {
90     return Objects.hash(priorityCategory, index);
91   }
92 
93   @Override
94   public String toString() {
95     return String.format("OptionPriority(%s,%s)", priorityCategory, index);
96   }
97 
98   /**
99    * The priority of option values, in order of increasing priority.
100    *
101    * <p>In general, new values for options can only override values with a lower or equal priority.
102    * Option values provided in annotations in an options class are implicitly at the priority {@code
103    * DEFAULT}.
104    *
105    * <p>The ordering of the priorities is the source-code order. This is consistent with the
106    * automatically generated {@code compareTo} method as specified by the Java Language
107    * Specification. DO NOT change the source-code order of these values, or you will break code that
108    * relies on the ordering.
109    */
110   public enum PriorityCategory {
111 
112     /**
113      * The priority of values specified in the {@link Option} annotation. This should never be
114      * specified in calls to {@link OptionsParser#parse}.
115      */
116     DEFAULT,
117 
118     /**
119      * Overrides default options at runtime, while still allowing the values to be overridden
120      * manually.
121      */
122     COMPUTED_DEFAULT,
123 
124     /** For options coming from a configuration file or rc file. */
125     RC_FILE,
126 
127     /** For options coming from the command line. */
128     COMMAND_LINE,
129 
130     /** For options coming from invocation policy. */
131     INVOCATION_POLICY,
132 
133     /**
134      * This priority can be used to unconditionally override any user-provided options. This should
135      * be used rarely and with caution!
136      */
137     SOFTWARE_REQUIREMENT
138   }
139 }
140