blob: e167f946939067ab18a091d715ebfa9c9f8dc7d5 [file] [log] [blame]
Dave Borowitz9de65952012-08-13 16:09:45 -07001// Copyright 2012 Google Inc. 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
15package com.google.gitiles;
16
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070017import com.google.common.base.Optional;
Dave Borowitz9de65952012-08-13 16:09:45 -070018import com.google.common.base.Predicates;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.collect.ImmutableList;
21import com.google.common.collect.Iterables;
22
23import org.eclipse.jgit.lib.Config;
24import org.joda.time.Duration;
25
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070026import java.util.TimeZone;
Dave Borowitz9de65952012-08-13 16:09:45 -070027import java.util.concurrent.TimeUnit;
28import java.util.regex.Matcher;
29import java.util.regex.Pattern;
30
31/** Utilities for working with {@link Config} objects. */
32public class ConfigUtil {
33 /**
34 * Read a duration value from the configuration.
35 * <p>
Dave Borowitz133c1e72015-12-02 12:56:07 -050036 * Durations can be written with unit suffixes, for example {@code "1 s"} or
Dave Borowitz9de65952012-08-13 16:09:45 -070037 * {@code "5 days"}. If units are not specified, milliseconds are assumed.
38 *
39 * @param config JGit config object.
40 * @param section section to read, e.g. "google"
41 * @param subsection subsection to read, e.g. "bigtable"
42 * @param name variable to read, e.g. "deadline".
43 * @param defaultValue value to use when the value is not assigned.
44 * @return a standard duration representing the time read, or defaultValue.
45 */
46 public static Duration getDuration(Config config, String section, String subsection, String name,
47 Duration defaultValue) {
48 String valStr = config.getString(section, subsection, name);
49 if (valStr == null) {
50 return defaultValue;
51 }
Dave Borowitz9de65952012-08-13 16:09:45 -070052 valStr = valStr.trim();
Dave Borowitz133c1e72015-12-02 12:56:07 -050053 if (valStr.isEmpty()) {
Dave Borowitz9de65952012-08-13 16:09:45 -070054 return defaultValue;
55 }
Dave Borowitz133c1e72015-12-02 12:56:07 -050056 Duration val = parseDuration(valStr);
57 if (val == null) {
Dave Borowitz9de65952012-08-13 16:09:45 -070058 String key = section + (subsection != null ? "." + subsection : "") + "." + name;
59 throw new IllegalStateException("Not time unit: " + key + " = " + valStr);
60 }
Dave Borowitz133c1e72015-12-02 12:56:07 -050061 return val;
62 }
63
64 /**
65 * Parse a duration value from a string.
66 * <p>
67 * Durations can be written with unit suffixes, for example {@code "1 s"} or
68 * {@code "5 days"}. If units are not specified, milliseconds are assumed.
69 *
70 * @param valStr the value to parse.
71 * @return a standard duration representing the time parsed, or null if not a
72 * valid duration.
73 */
74 public static Duration parseDuration(String valStr) {
75 if (valStr == null) {
76 return null;
77 }
78 valStr = valStr.trim();
79 if (valStr.isEmpty()) {
80 return null;
81 }
82 Matcher m = matcher("^([1-9][0-9]*(?:\\.[0-9]*)?)\\s*(.*)$", valStr);
83 if (!m.matches()) {
84 return null;
85 }
Dave Borowitz9de65952012-08-13 16:09:45 -070086
87 String digits = m.group(1);
88 String unitName = m.group(2).trim();
89
90 TimeUnit unit;
91 if ("".equals(unitName)) {
92 unit = TimeUnit.MILLISECONDS;
93 } else if (anyOf(unitName, "ms", "millis", "millisecond", "milliseconds")) {
94 unit = TimeUnit.MILLISECONDS;
95 } else if (anyOf(unitName, "s", "sec", "second", "seconds")) {
96 unit = TimeUnit.SECONDS;
97 } else if (anyOf(unitName, "m", "min", "minute", "minutes")) {
98 unit = TimeUnit.MINUTES;
99 } else if (anyOf(unitName, "h", "hr", "hour", "hours")) {
100 unit = TimeUnit.HOURS;
101 } else if (anyOf(unitName, "d", "day", "days")) {
102 unit = TimeUnit.DAYS;
103 } else {
Dave Borowitz133c1e72015-12-02 12:56:07 -0500104 return null;
Dave Borowitz9de65952012-08-13 16:09:45 -0700105 }
106
107 try {
108 if (digits.indexOf('.') == -1) {
109 long val = Long.parseLong(digits);
110 return new Duration(val * TimeUnit.MILLISECONDS.convert(1, unit));
111 } else {
112 double val = Double.parseDouble(digits);
113 return new Duration((long) (val * TimeUnit.MILLISECONDS.convert(1, unit)));
114 }
115 } catch (NumberFormatException nfe) {
Dave Borowitz133c1e72015-12-02 12:56:07 -0500116 return null;
Dave Borowitz9de65952012-08-13 16:09:45 -0700117 }
118 }
119
120 /**
121 * Get a {@link CacheBuilder} from a config.
122 *
123 * @param config JGit config object.
124 * @param name name of the cache subsection under the "cache" section.
125 * @return a new cache builder.
126 */
127 public static CacheBuilder<Object, Object> getCacheBuilder(Config config, String name) {
Dave Borowitzddd96b82014-04-18 10:57:18 -0700128 CacheBuilder<Object, Object> b = CacheBuilder.newBuilder();
Dave Borowitz9de65952012-08-13 16:09:45 -0700129 try {
130 if (config.getString("cache", name, "maximumWeight") != null) {
131 b.maximumWeight(config.getLong("cache", name, "maximumWeight", 20 << 20));
132 }
133 if (config.getString("cache", name, "maximumSize") != null) {
134 b.maximumSize(config.getLong("cache", name, "maximumSize", 16384));
135 }
136 Duration expireAfterWrite = getDuration(config, "cache", name, "expireAfterWrite", null);
137 if (expireAfterWrite != null) {
138 b.expireAfterWrite(expireAfterWrite.getMillis(), TimeUnit.MILLISECONDS);
139 }
140 Duration expireAfterAccess = getDuration(config, "cache", name, "expireAfterAccess", null);
141 if (expireAfterAccess != null) {
142 b.expireAfterAccess(expireAfterAccess.getMillis(), TimeUnit.MILLISECONDS);
143 }
144 // Add other methods as needed.
145 } catch (IllegalArgumentException e) {
146 throw new IllegalArgumentException("Error getting CacheBuilder for " + name, e);
147 } catch (IllegalStateException e) {
148 throw new IllegalStateException("Error getting CacheBuilder for " + name, e);
149 }
150 return b;
151 }
152
Dave Borowitz2b2f34b2014-04-29 16:47:20 -0700153 /**
154 * Get a {@link TimeZone} from a config.
155 *
156 * @param config JGit config object.
157 * @param section section to read, e.g. "gitiles".
158 * @param subsection subsection to read, e.g. "subsection".
159 * @param name variable to read, e.g. "fixedTimeZone".
160 * @return a time zone read from parsing the specified config string value, or
161 * {@link Optional#absent()} if not present. As in the behavior of
162 * {@link TimeZone#getTimeZone(String)}, unknown time zones are treated as
163 * GMT.
164 */
165 public static Optional<TimeZone> getTimeZone(Config config, String section, String subsection,
166 String name) {
167 String id = config.getString(section, subsection, name);
168 return id != null ? Optional.of(TimeZone.getTimeZone(id)) : Optional.<TimeZone> absent();
169 }
170
Dave Borowitz9de65952012-08-13 16:09:45 -0700171 private static Matcher matcher(String pattern, String valStr) {
172 return Pattern.compile(pattern).matcher(valStr);
173 }
174
175 private static boolean anyOf(String a, String... cases) {
176 return Iterables.any(ImmutableList.copyOf(cases),
177 Predicates.equalTo(a.toLowerCase()));
178 }
179
180 private ConfigUtil() {
181 }
182}