]> source.dussan.org Git - sonar-scanner-cli.git/commitdiff
SQSCANNER-9 Allow to use variables in the configuration file
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 23 Feb 2017 08:55:29 +0000 (09:55 +0100)
committerDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 23 Feb 2017 15:01:57 +0000 (16:01 +0100)
src/main/java/org/sonarsource/scanner/cli/Conf.java
src/main/java/org/sonarsource/scanner/cli/PropertyResolver.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/MainTest.java
src/test/java/org/sonarsource/scanner/cli/PropertyResolverTest.java [new file with mode: 0644]

index 9facab1e5a86aafc1f93a47a9b82cb795401a078..8bfe39cc44e7435ed060543209b9e8c69c7b2353 100644 (file)
@@ -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 (file)
index 0000000..d1fe2c8
--- /dev/null
@@ -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;
+
+  }
+}
index 59606b2cc24acc8699758a93d2767149cb7ba978..59da205bc84d63928247e9811b55fb11da241d2e 100644 (file)
@@ -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 (file)
index 0000000..659d4a8
--- /dev/null
@@ -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();
+  }
+}