blob: 0fedbf431cbc12f0f9388966969857e29fe9aa29 [file] [log] [blame]
// Copyright 2012 Google Inc. 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.gitiles;
import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.eclipse.jgit.lib.Config;
import org.joda.time.Duration;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** Utilities for working with {@link Config} objects. */
public class ConfigUtil {
/**
* Read a duration value from the configuration.
* <p>
* Durations can be written with unit suffixes, for example {@code "1 s"} or
* {@code "5 days"}. If units are not specified, milliseconds are assumed.
*
* @param config JGit config object.
* @param section section to read, e.g. "google"
* @param subsection subsection to read, e.g. "bigtable"
* @param name variable to read, e.g. "deadline".
* @param defaultValue value to use when the value is not assigned.
* @return a standard duration representing the time read, or defaultValue.
*/
public static Duration getDuration(
Config config, String section, String subsection, String name, Duration defaultValue) {
String valStr = config.getString(section, subsection, name);
if (valStr == null) {
return defaultValue;
}
valStr = valStr.trim();
if (valStr.isEmpty()) {
return defaultValue;
}
Duration val = parseDuration(valStr);
if (val == null) {
String key = section + (subsection != null ? "." + subsection : "") + "." + name;
throw new IllegalStateException("Not time unit: " + key + " = " + valStr);
}
return val;
}
/**
* Parse a duration value from a string.
* <p>
* Durations can be written with unit suffixes, for example {@code "1 s"} or
* {@code "5 days"}. If units are not specified, milliseconds are assumed.
*
* @param valStr the value to parse.
* @return a standard duration representing the time parsed, or null if not a
* valid duration.
*/
public static Duration parseDuration(String valStr) {
if (valStr == null) {
return null;
}
valStr = valStr.trim();
if (valStr.isEmpty()) {
return null;
}
Matcher m = matcher("^([1-9][0-9]*(?:\\.[0-9]*)?)\\s*(.*)$", valStr);
if (!m.matches()) {
return null;
}
String digits = m.group(1);
String unitName = m.group(2).trim();
TimeUnit unit;
if ("".equals(unitName)) {
unit = TimeUnit.MILLISECONDS;
} else if (anyOf(unitName, "ms", "millis", "millisecond", "milliseconds")) {
unit = TimeUnit.MILLISECONDS;
} else if (anyOf(unitName, "s", "sec", "second", "seconds")) {
unit = TimeUnit.SECONDS;
} else if (anyOf(unitName, "m", "min", "minute", "minutes")) {
unit = TimeUnit.MINUTES;
} else if (anyOf(unitName, "h", "hr", "hour", "hours")) {
unit = TimeUnit.HOURS;
} else if (anyOf(unitName, "d", "day", "days")) {
unit = TimeUnit.DAYS;
} else {
return null;
}
try {
if (digits.indexOf('.') == -1) {
long val = Long.parseLong(digits);
return new Duration(val * TimeUnit.MILLISECONDS.convert(1, unit));
} else {
double val = Double.parseDouble(digits);
return new Duration((long) (val * TimeUnit.MILLISECONDS.convert(1, unit)));
}
} catch (NumberFormatException nfe) {
return null;
}
}
/**
* Get a {@link CacheBuilder} from a config.
*
* @param config JGit config object.
* @param name name of the cache subsection under the "cache" section.
* @return a new cache builder.
*/
public static CacheBuilder<Object, Object> getCacheBuilder(Config config, String name) {
CacheBuilder<Object, Object> b = CacheBuilder.newBuilder();
try {
if (config.getString("cache", name, "maximumWeight") != null) {
b.maximumWeight(config.getLong("cache", name, "maximumWeight", 20 << 20));
}
if (config.getString("cache", name, "maximumSize") != null) {
b.maximumSize(config.getLong("cache", name, "maximumSize", 16384));
}
Duration expireAfterWrite = getDuration(config, "cache", name, "expireAfterWrite", null);
if (expireAfterWrite != null) {
b.expireAfterWrite(expireAfterWrite.getMillis(), TimeUnit.MILLISECONDS);
}
Duration expireAfterAccess = getDuration(config, "cache", name, "expireAfterAccess", null);
if (expireAfterAccess != null) {
b.expireAfterAccess(expireAfterAccess.getMillis(), TimeUnit.MILLISECONDS);
}
// Add other methods as needed.
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Error getting CacheBuilder for " + name, e);
} catch (IllegalStateException e) {
throw new IllegalStateException("Error getting CacheBuilder for " + name, e);
}
return b;
}
/**
* Get a {@link TimeZone} from a config.
*
* @param config JGit config object.
* @param section section to read, e.g. "gitiles".
* @param subsection subsection to read, e.g. "subsection".
* @param name variable to read, e.g. "fixedTimeZone".
* @return a time zone read from parsing the specified config string value, or
* {@link Optional#absent()} if not present. As in the behavior of
* {@link TimeZone#getTimeZone(String)}, unknown time zones are treated as
* GMT.
*/
public static Optional<TimeZone> getTimeZone(
Config config, String section, String subsection, String name) {
String id = config.getString(section, subsection, name);
return id != null ? Optional.of(TimeZone.getTimeZone(id)) : Optional.<TimeZone>absent();
}
private static Matcher matcher(String pattern, String valStr) {
return Pattern.compile(pattern).matcher(valStr);
}
private static boolean anyOf(String a, String... cases) {
return Iterables.any(ImmutableList.copyOf(cases), Predicates.equalTo(a.toLowerCase()));
}
private ConfigUtil() {}
}