/amps-maven-plugin/src/main/java/com/atlassian/maven/plugins/amps/util/ConfigFileUtils.java
Java | 267 lines | 162 code | 31 blank | 74 comment | 23 complexity | afb3c4a9ec5972f431a7b9aaa499bcac MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
- package com.atlassian.maven.plugins.amps.util;
- import org.apache.maven.plugin.MojoExecutionException;
- import javax.annotation.ParametersAreNonnullByDefault;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.util.List;
- import java.util.Map;
- import java.util.Properties;
- import static java.nio.charset.StandardCharsets.UTF_8;
- import static java.util.Objects.hash;
- import static java.util.Objects.requireNonNull;
- import static org.apache.commons.io.FileUtils.readFileToString;
- import static org.apache.commons.io.FileUtils.writeStringToFile;
- /**
- * Utility methods relating to configuration files.
- */
- @ParametersAreNonnullByDefault
- public final class ConfigFileUtils {
- /**
- * Makes the given replacements within each of the given files.
- *
- * @param files the files to modify; any that don't exist are quietly skipped
- * @param replacements the replacements to make
- * @param inverted if you want to swap values with keys. Be aware that the list is processed in order,
- * so that if 2 keys have the same value, the first key will be chosen. The Replacement records with
- * reversible set to false will not be reversed. Default: false.
- * @throws MojoExecutionException if something goes wrong
- */
- public static void replace(final List<File> files, final List<Replacement> replacements, final boolean inverted)
- throws MojoExecutionException {
- for (File file : files) {
- if (file.exists()) {
- replace(file, replacements, inverted);
- }
- }
- }
- private static void replace(final File cfgFile, final List<Replacement> replacements, final boolean inverted)
- throws MojoExecutionException {
- try {
- String config = readFileToString(cfgFile, UTF_8);
- if (!inverted) {
- for (Replacement replacement : replacements) {
- if (replacement.applyWhenUnzipping()) {
- config = replacement.replace(config);
- }
- }
- } else {
- for (Replacement replacement : replacements) {
- config = replacement.reverse(config);
- }
- }
- writeStringToFile(cfgFile, config, UTF_8);
- } catch (IOException ex) {
- throw new MojoExecutionException("Unable to replace " + cfgFile, ex);
- }
- }
- /**
- * Modifies the given file by replacing the given pattern with the given replacement.
- *
- * @param file the file to modify; if this does not exist or is a directory, this method quietly does nothing
- * @param pattern the pattern to replace
- * @param replacement the replacement
- * @throws MojoExecutionException if there's an I/O problem
- * @see String#replaceAll(String, String) for how the pattern and replacement work
- */
- public static void replaceAll(final File file, final String pattern, final String replacement)
- throws MojoExecutionException {
- if (!file.isFile()) {
- return;
- }
- try {
- final String oldContents = readFileToString(file, UTF_8);
- final String newContents = oldContents.replaceAll(pattern, replacement); // uses regex
- writeStringToFile(file, newContents, UTF_8);
- } catch (IOException ex) {
- throw new MojoExecutionException("Unable to replace " + file, ex);
- }
- }
- /**
- * Updates the given properties file with the given map of properties.
- *
- * @param propertiesFile the properties file to update
- * @param newProperties the properties to add/update in the file
- */
- public static void updateProperties(final File propertiesFile, final Map<String, String> newProperties) {
- final Properties props = readProperties(propertiesFile);
- newProperties.forEach(props::setProperty);
- try (final OutputStream out = new FileOutputStream(propertiesFile)) {
- props.store(out, "Processed by AMPS");
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
- private static Properties readProperties(final File propertiesFile) {
- final Properties props = new Properties();
- try (final InputStream in = new FileInputStream(propertiesFile)) {
- props.load(in);
- } catch (final FileNotFoundException ignored) {
- // Ignore
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- return props;
- }
- /**
- * Represents a replacement in a configuration file or set of files.
- */
- public static class Replacement implements Comparable<Replacement> {
- /**
- * Factory method for a {@link Replacement} that applies only when <em>unzipping</em> the home directory.
- *
- * @param key the key
- * @param value the value
- * @return a new instance
- */
- public static Replacement onlyWhenUnzipping(final String key, final String value) {
- return new Replacement(key, value, true, false);
- }
- private final String key;
- private final String value;
- /**
- * Replace the key with the value when unzipping a home. This is the normal meaning of
- * a replacement, {@code key -> value}
- */
- private final boolean applyWhenUnzipping;
- /**
- * Detect the value and replace it with the key when zipping a home directory
- */
- private final boolean reversible;
- /**
- * Represents a key to be replaced in the configuration files.
- * <p>
- * <p/>
- * <b>Important</b>: If your value is short, such as "/", "", "true", "false", please set reversible=false.
- * When zipping a home, config files are parsed and everything is replaced back with keys, such as %PRODUCT_HOME_DIR%.
- * If you provide a string with false positives, you may parametrise too many variables.
- *
- * @param key the key to be replaced. Must not be null.
- * @param value the value to be replaced. Must not be null. <b>Important</b>: If short, such as / or "", please set reversible=false.
- */
- public Replacement(final String key, final String value) {
- this(key, value, true);
- }
- /**
- * Represents a key to be replaced in the configuration files.
- *
- * @param key the key to be replaced. Must not be null.
- * @param value the value to be replaced. Must not be null.
- * @param reversible true if the value should be replaced with the key before
- * preparing a snapshot. Default is true. Use false when:<ul>
- * <li>the value is non-unique, e.g. "%BAMBOO_ENABLED% = true" should not be reversible.</li>
- * <li>we only support the value for legacy, but we wouldn't re-wrap a snapshot with this key</li>
- * </ul>
- */
- public Replacement(final String key, final String value, final boolean reversible) {
- this(key, value, true, reversible);
- }
- /**
- * @param key the key, never null
- * @param value the value, never null
- * @param applyWhenUnzipping apply when unzipping a home. Defaults to true.
- * @param reversible apply when zipping a home. Defaults to true.
- */
- Replacement(final String key, final String value, final boolean applyWhenUnzipping, final boolean reversible) {
- this.key = requireNonNull(key, "key must not be null");
- this.value = requireNonNull(value, "value must not be null");
- this.applyWhenUnzipping = applyWhenUnzipping;
- this.reversible = reversible;
- }
- public final String replace(final String s) {
- return replace(s, key, value);
- }
- public final String reverse(final String s) {
- return reversible ? replace(s, value, key) : s;
- }
- protected String replace(final String s, final String target, final String replacement) {
- return s.replace(target, replacement);
- }
- public boolean applyWhenUnzipping() {
- return applyWhenUnzipping;
- }
- @Override
- public boolean equals(final Object other) {
- if (this == other) {
- return true;
- }
- if (other == null || getClass() != other.getClass()) {
- return false;
- }
- final Replacement that = (Replacement) other;
- return applyWhenUnzipping == that.applyWhenUnzipping &&
- reversible == that.reversible &&
- key.equals(that.key) &&
- value.equals(that.value);
- }
- @Override
- public int hashCode() {
- return hash(key, value, applyWhenUnzipping, reversible);
- }
- @Override
- public int compareTo(final Replacement other) {
- int length1 = this.value.length();
- int length2 = other.value.length();
- return length2 - length1;
- }
- @Override
- public String toString() {
- final String operation;
- if (applyWhenUnzipping && reversible) {
- operation = " <-> ";
- } else if (applyWhenUnzipping) {
- operation = " -> ";
- } else if (reversible) {
- operation = " <- ";
- } else {
- operation = " (nop) ";
- }
- return key + operation + value;
- }
- }
- public static final class RegexReplacement extends Replacement {
- public RegexReplacement(final String key, final String value) {
- super(key, value, false);
- }
- @Override
- protected String replace(final String s, final String target, final String replacement) {
- return s.replaceAll(target, replacement);
- }
- }
- private ConfigFileUtils() {}
- }