diff --git a/modules/core/src/main/java/net/ashald/envfile/providers/dotenv/DotEnvFileParser.java b/modules/core/src/main/java/net/ashald/envfile/providers/dotenv/DotEnvFileParser.java index 8cfe250..3b2b54d 100644 --- a/modules/core/src/main/java/net/ashald/envfile/providers/dotenv/DotEnvFileParser.java +++ b/modules/core/src/main/java/net/ashald/envfile/providers/dotenv/DotEnvFileParser.java @@ -1,18 +1,18 @@ package net.ashald.envfile.providers.dotenv; -import net.ashald.envfile.AbstractEnvVarsProvider; -import net.ashald.envfile.EnvFileErrorException; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.jetbrains.annotations.NotNull; + +import net.ashald.envfile.AbstractEnvVarsProvider; +import net.ashald.envfile.EnvFileErrorException; + public class DotEnvFileParser extends AbstractEnvVarsProvider { public DotEnvFileParser(boolean shouldSubstituteEnvVar) { @@ -26,13 +26,36 @@ protected Map getEnvVars(@NotNull Map runConfigE try { List lines = Files.readAllLines(Paths.get(path), StandardCharsets.UTF_8); + String multiLineKey = null; + StringBuilder multiLineValueAccumulator = null; for (String l: lines) { String strippedLine = l.trim(); - if (!strippedLine.startsWith("#") && strippedLine.contains("=")) { + if (strippedLine.startsWith("#")) { + continue; + } + + if(multiLineValueAccumulator != null) { + String strippedLineWithoutComments = removeComments(strippedLine); + int doubleQuoteIndex = strippedLineWithoutComments.indexOf('"'); + if(doubleQuoteIndex > -1) { + multiLineValueAccumulator.append("\n").append(strippedLineWithoutComments, 0, doubleQuoteIndex); + result.put(multiLineKey, multiLineValueAccumulator.toString()); + multiLineKey = null; + multiLineValueAccumulator = null; + } else { + multiLineValueAccumulator.append("\n").append(strippedLineWithoutComments); + } + } else if (strippedLine.contains("=")) { String[] tokens = strippedLine.split("=", 2); String key = tokens[0]; - String value = trim(tokens[1]); - result.put(key, value); + String rawValue = tokens[1].trim(); + if(rawValue.startsWith("\"") && !rawValue.endsWith("\"")) { + multiLineKey = key; + multiLineValueAccumulator = new StringBuilder(removeComments(rawValue.substring(1))); + } else { + String value = trim(rawValue); + result.put(key, value); + } } } } catch (IOException ex) { @@ -46,8 +69,12 @@ private static String trim(String value) { String trimmed = value.trim(); if ((trimmed.startsWith("\"") && trimmed.endsWith("\"")) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) - return trimmed.substring(1, trimmed.length() - 1); + return trimmed.substring(1, trimmed.length() - 1).replace("\\n", "\n"); + + return removeComments(trimmed); + } + private static String removeComments(String trimmed) { return trimmed.replaceAll("\\s#.*$", "").replaceAll("(\\s)\\\\#", "$1#").trim(); } } diff --git a/modules/core/src/test/java/net/ashald/envfile/providers/dotenv/DotEnvFileParserTest.java b/modules/core/src/test/java/net/ashald/envfile/providers/dotenv/DotEnvFileParserTest.java index 793d85f..85546bb 100644 --- a/modules/core/src/test/java/net/ashald/envfile/providers/dotenv/DotEnvFileParserTest.java +++ b/modules/core/src/test/java/net/ashald/envfile/providers/dotenv/DotEnvFileParserTest.java @@ -1,15 +1,15 @@ package net.ashald.envfile.providers.dotenv; -import net.ashald.envfile.EnvFileErrorException; -import org.junit.Assert; -import org.junit.Test; - import java.io.IOException; import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Map; +import org.junit.Assert; +import org.junit.Test; + +import net.ashald.envfile.EnvFileErrorException; + public class DotEnvFileParserTest { private DotEnvFileParser parser = new DotEnvFileParser(true); @@ -67,4 +67,21 @@ public void testOrder() throws EnvFileErrorException, IOException { Assert.assertEquals("A(B(C))", result.get("A")); } + @Test + public void testMultiLineVariables() throws EnvFileErrorException { + Map result = parser.getEnvVars(Collections.emptyMap(), getFile("multi-line-variable.env")); + Assert.assertEquals(1, result.size()); + Assert.assertEquals("-----BEGIN RSA PRIVATE KEY-----\nHkVN9...\n-----END DSA PRIVATE KEY-----\n", result.get("PRIVATE_KEY")); + } + + @Test + public void testMultiLineVariablesWithLineBreaks() throws EnvFileErrorException { + Map result = parser.getEnvVars(Collections.emptyMap(), getFile("multi-line-variable-with-line-breaks.env")); + Assert.assertEquals(1, result.size()); + Assert.assertEquals("-----BEGIN RSA PRIVATE KEY-----\n" + + "...\n" + + "HkVN9...\n" + + "...\n" + + "-----END DSA PRIVATE KEY-----", result.get("PRIVATE_KEY")); + } } diff --git a/modules/core/src/test/resources/providers/dotenv/multi-line-variable-with-line-breaks.env b/modules/core/src/test/resources/providers/dotenv/multi-line-variable-with-line-breaks.env new file mode 100644 index 0000000..fe5c579 --- /dev/null +++ b/modules/core/src/test/resources/providers/dotenv/multi-line-variable-with-line-breaks.env @@ -0,0 +1,5 @@ +PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY----- +... # random comment with a " in it +HkVN9... # a second one +... +-----END DSA PRIVATE KEY-----" diff --git a/modules/core/src/test/resources/providers/dotenv/multi-line-variable.env b/modules/core/src/test/resources/providers/dotenv/multi-line-variable.env new file mode 100644 index 0000000..9dcaa5b --- /dev/null +++ b/modules/core/src/test/resources/providers/dotenv/multi-line-variable.env @@ -0,0 +1 @@ +PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nHkVN9...\n-----END DSA PRIVATE KEY-----\n"