aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2017-02-23 09:55:29 +0100
committerDuarte Meneses <duarte.meneses@sonarsource.com>2017-02-23 16:01:57 +0100
commitdf0aa9bad95dd1dc3181f5ab59bb9746123cd679 (patch)
treed55634390ed9117534377c35f1e7b73e4a4542d0 /src
parent4a2bdf64e5717608eb1a997e356932278896f051 (diff)
downloadsonar-scanner-cli-df0aa9bad95dd1dc3181f5ab59bb9746123cd679.tar.gz
sonar-scanner-cli-df0aa9bad95dd1dc3181f5ab59bb9746123cd679.zip
SQSCANNER-9 Allow to use variables in the configuration file
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/sonarsource/scanner/cli/Conf.java7
-rw-r--r--src/main/java/org/sonarsource/scanner/cli/PropertyResolver.java104
-rw-r--r--src/test/java/org/sonarsource/scanner/cli/MainTest.java2
-rw-r--r--src/test/java/org/sonarsource/scanner/cli/PropertyResolverTest.java123
4 files changed, 235 insertions, 1 deletions
diff --git a/src/main/java/org/sonarsource/scanner/cli/Conf.java b/src/main/java/org/sonarsource/scanner/cli/Conf.java
index 9facab1..8bfe39c 100644
--- a/src/main/java/org/sonarsource/scanner/cli/Conf.java
+++ b/src/main/java/org/sonarsource/scanner/cli/Conf.java
@@ -62,12 +62,19 @@ class Conf {
result.putAll(System.getProperties());
result.putAll(loadEnvironmentProperties());
result.putAll(cli.properties());
+ result = resolve(result);
+
// root project base directory must be present and be absolute
result.setProperty(PROPERTY_PROJECT_BASEDIR, getRootProjectBaseDir(result).toString());
result.remove(PROJECT_HOME);
return result;
}
+ private Properties resolve(Properties props) {
+ PropertyResolver resolver = new PropertyResolver(props, env);
+ return resolver.resolve();
+ }
+
private Properties loadEnvironmentProperties() {
return Utils.loadEnvironmentProperties(env);
}
diff --git a/src/main/java/org/sonarsource/scanner/cli/PropertyResolver.java b/src/main/java/org/sonarsource/scanner/cli/PropertyResolver.java
new file mode 100644
index 0000000..d1fe2c8
--- /dev/null
+++ b/src/main/java/org/sonarsource/scanner/cli/PropertyResolver.java
@@ -0,0 +1,104 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarsource.scanner.cli;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PropertyResolver {
+ private static final Pattern placeholderPattern = Pattern.compile("\\$\\{([\\w\\.]+)\\}|\\$([\\w\\.]+)");
+ private final Properties props;
+ private final Properties resolved;
+ private final List<String> queue;
+ private Map<String, String> env;
+
+ public PropertyResolver(Properties props, Map<String, String> env) {
+ this.props = props;
+ this.env = env;
+ this.resolved = new Properties();
+ this.queue = new LinkedList<>();
+ }
+
+ public Properties resolve() {
+ for (Map.Entry<Object, Object> e : props.entrySet()) {
+ if (resolved.containsKey(e.getKey())) {
+ continue;
+ }
+ resolveProperty((String) e.getKey());
+ }
+
+ return resolved;
+ }
+
+ private String getValue(String key) {
+ String propValue;
+
+ if (key.startsWith("env.")) {
+ String envKey = key.substring(4);
+ propValue = env.get(envKey);
+ } else {
+ propValue = props.getProperty(key);
+ }
+
+ return propValue != null ? propValue : "";
+ }
+
+ private String resolveProperty(String propKey) {
+ String propValue = getValue(propKey);
+ if (propValue.isEmpty()) {
+ return propValue;
+ }
+
+ Matcher m = placeholderPattern.matcher(propValue);
+ StringBuffer sb = new StringBuffer();
+
+ while (m.find()) {
+ String varName = (null == m.group(1)) ? m.group(2) : m.group(1);
+ if (queue.contains(varName)) {
+ throw new IllegalArgumentException("Found a loop resolving place holders in properties, for variable: " + varName);
+ }
+
+ String placeholderValue = resolveVar(varName);
+ m.appendReplacement(sb, Matcher.quoteReplacement(placeholderValue));
+ }
+ m.appendTail(sb);
+
+ String resolvedPropValue = sb.toString();
+ resolved.setProperty(propKey, resolvedPropValue);
+ return resolvedPropValue;
+ }
+
+ private String resolveVar(String varName) {
+ String placeholderValue;
+ if (resolved.containsKey(varName)) {
+ placeholderValue = resolved.getProperty(varName);
+ } else {
+ queue.add(varName);
+ placeholderValue = resolveProperty(varName);
+ queue.remove(varName);
+ }
+ return placeholderValue;
+
+ }
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/MainTest.java b/src/test/java/org/sonarsource/scanner/cli/MainTest.java
index 59606b2..59da205 100644
--- a/src/test/java/org/sonarsource/scanner/cli/MainTest.java
+++ b/src/test/java/org/sonarsource/scanner/cli/MainTest.java
@@ -64,7 +64,7 @@ public class MainTest {
when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
when(conf.properties()).thenReturn(properties);
}
-
+
@Test
public void should_execute_runner() {
Main main = new Main(exit, cli, conf, runnerFactory, logs);
diff --git a/src/test/java/org/sonarsource/scanner/cli/PropertyResolverTest.java b/src/test/java/org/sonarsource/scanner/cli/PropertyResolverTest.java
new file mode 100644
index 0000000..659d4a8
--- /dev/null
+++ b/src/test/java/org/sonarsource/scanner/cli/PropertyResolverTest.java
@@ -0,0 +1,123 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarsource.scanner.cli;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class PropertyResolverTest {
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Test
+ public void resolve_properties() {
+ Properties map = new Properties();
+ Map<String, String> env = new HashMap<>();
+
+ // resolve
+ map.put("A", "value a");
+ map.put("B", "value b");
+ map.put("C", "${A} ${B} ${nonexisting}");
+
+ PropertyResolver resolver = new PropertyResolver(map, env);
+ Properties resolved = resolver.resolve();
+ assertThat(resolved.get("A")).isEqualTo("value a");
+ assertThat(resolved.get("B")).isEqualTo("value b");
+ assertThat(resolved.get("C")).isEqualTo("value a value b ");
+
+ map.clear();
+ map.put("sonar.login", "admin");
+ map.put("sonar.password", "${sonar.login}");
+
+ resolver = new PropertyResolver(map, env);
+ resolved = resolver.resolve();
+ assertThat(resolved.get("sonar.password")).isEqualTo("admin");
+ }
+
+ @Test
+ public void use_env() {
+ Properties map = new Properties();
+ Map<String, String> env = new HashMap<>();
+
+ // resolve
+ map.put("A", "invalid");
+ map.put("B", "value b");
+ map.put("C", "${env.A} ${B} ${nonexisting}");
+ env.put("A", "value a");
+
+ PropertyResolver resolver = new PropertyResolver(map, env);
+ Properties resolved = resolver.resolve();
+ assertThat(resolved.get("A")).isEqualTo("invalid");
+ assertThat(resolved.get("B")).isEqualTo("value b");
+ assertThat(resolved.get("C")).isEqualTo("value a value b ");
+ }
+
+ @Test
+ public void resolve_recursively() {
+ Properties map = new Properties();
+ Map<String, String> env = new HashMap<>();
+ map.put("A", "value a");
+ map.put("B", "${A}");
+ map.put("C", "${A} ${B}");
+
+ PropertyResolver resolver = new PropertyResolver(map, env);
+ Properties resolved = resolver.resolve();
+ assertThat(resolved.get("A")).isEqualTo("value a");
+ assertThat(resolved.get("B")).isEqualTo("value a");
+ assertThat(resolved.get("C")).isEqualTo("value a value a");
+ }
+
+ @Test
+ public void dont_resolve_nested() {
+ Properties map = new Properties();
+ Map<String, String> env = new HashMap<>();
+ map.put("A", "value a");
+ map.put("B", "value b");
+ map.put("C", "${A ${B}}");
+
+ PropertyResolver resolver = new PropertyResolver(map, env);
+ Properties resolved = resolver.resolve();
+ assertThat(resolved.get("A")).isEqualTo("value a");
+ assertThat(resolved.get("B")).isEqualTo("value b");
+ assertThat(resolved.get("C")).isEqualTo("${A value b}");
+ }
+
+ @Test
+ public void fail_loop_properties_resolution() {
+ Properties map = new Properties();
+ Map<String, String> env = new HashMap<>();
+
+ // resolve
+ map.put("A", "${B}");
+ map.put("B", "${A}");
+
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("variable: B");
+ PropertyResolver resolver = new PropertyResolver(map, env);
+ resolver.resolve();
+ }
+}