From a502d96a860456ec5e8c96761db70f7cabb74751 Mon Sep 17 00:00:00 2001 From: Paul Martin <paul@paulsputer.com> Date: Sat, 30 Apr 2016 04:19:14 -0400 Subject: [PATCH] Merge pull request #1073 from gitblit/1062-DocEditorUpdates --- src/main/java/com/gitblit/FileSettings.java | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gitblit/FileSettings.java b/src/main/java/com/gitblit/FileSettings.java index 12739d2..3caf966 100644 --- a/src/main/java/com/gitblit/FileSettings.java +++ b/src/main/java/com/gitblit/FileSettings.java @@ -18,10 +18,13 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; import java.util.Map; import java.util.Properties; import com.gitblit.utils.FileUtils; +import com.gitblit.utils.StringUtils; /** * Dynamically loads and reloads a properties file by keeping track of the last @@ -32,7 +35,7 @@ */ public class FileSettings extends IStoredSettings { - protected final File propertiesFile; + protected File propertiesFile; private final Properties properties = new Properties(); @@ -40,9 +43,32 @@ private volatile boolean forceReload; - public FileSettings(String file) { + public FileSettings() { super(FileSettings.class); + } + + public FileSettings(String file) { + this(); + load(file); + } + + public void load(String file) { this.propertiesFile = new File(file); + } + + /** + * Merges the provided settings into this instance. This will also + * set the target file for this instance IFF it is unset AND the merge + * source is also a FileSettings. This is a little sneaky. + */ + @Override + public void merge(IStoredSettings settings) { + super.merge(settings); + + // sneaky: set the target file from the merge source + if (propertiesFile == null && settings instanceof FileSettings) { + this.propertiesFile = ((FileSettings) settings).propertiesFile; + } } /** @@ -51,12 +77,16 @@ */ @Override protected synchronized Properties read() { - if (propertiesFile.exists() && (forceReload || (propertiesFile.lastModified() > lastModified))) { + if (propertiesFile != null && propertiesFile.exists() && (forceReload || (propertiesFile.lastModified() > lastModified))) { FileInputStream is = null; try { + logger.debug("loading {}", propertiesFile); Properties props = new Properties(); is = new FileInputStream(propertiesFile); props.load(is); + + // ticket-110 + props = readIncludes(props); // load properties after we have successfully read file properties.clear(); @@ -81,6 +111,79 @@ } /** + * Recursively read "include" properties files. + * + * @param properties + * @return + * @throws IOException + */ + private Properties readIncludes(Properties properties) throws IOException { + + Properties baseProperties = new Properties(); + + String include = (String) properties.remove("include"); + if (!StringUtils.isEmpty(include)) { + + // allow for multiples + List<String> names = StringUtils.getStringsFromValue(include, ","); + for (String name : names) { + + if (StringUtils.isEmpty(name)) { + continue; + } + + // try co-located + File file = new File(propertiesFile.getParentFile(), name.trim()); + if (!file.exists()) { + // try absolute path + file = new File(name.trim()); + } + + if (!file.exists()) { + logger.warn("failed to locate {}", file); + continue; + } + + // load properties + logger.debug("loading {}", file); + try (FileInputStream iis = new FileInputStream(file)) { + baseProperties.load(iis); + } + + // read nested includes + baseProperties = readIncludes(baseProperties); + + } + + } + + // includes are "default" properties, they must be set first and the + // props which specified the "includes" must override + Properties merged = new Properties(); + merged.putAll(baseProperties); + merged.putAll(properties); + + return merged; + } + + @Override + public boolean saveSettings() { + String content = FileUtils.readContent(propertiesFile, "\n"); + for (String key : removals) { + String regex = "(?m)^(" + regExEscape(key) + "\\s*+=\\s*+)" + + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$"; + content = content.replaceAll(regex, ""); + } + removals.clear(); + + FileUtils.writeContent(propertiesFile, content); + // manually set the forceReload flag because not all JVMs support real + // millisecond resolution of lastModified. (issue-55) + forceReload = true; + return true; + } + + /** * Updates the specified settings in the settings file. */ @Override @@ -88,7 +191,7 @@ String content = FileUtils.readContent(propertiesFile, "\n"); for (Map.Entry<String, String> setting:settings.entrySet()) { String regex = "(?m)^(" + regExEscape(setting.getKey()) + "\\s*+=\\s*+)" - + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$"; + + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$"; String oldContent = content; content = content.replaceAll(regex, setting.getKey() + " = " + setting.getValue()); if (content.equals(oldContent)) { -- Gitblit v1.9.1