]> source.dussan.org Git - sonar-scanner-cli.git/commitdiff
SONARPLUGINS-3575, SONARPLUGINS-3604, SONARPLUGINS-3574
authorJulien HENRY <julien.henry@sonarsource.com>
Thu, 3 Apr 2014 14:04:49 +0000 (16:04 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Thu, 3 Apr 2014 14:43:37 +0000 (16:43 +0200)
 * Move parsing of sonar-project.properties files to SQ Runner
 * Trim properties read from configuration files
 * Add an official property to specify a project baseDir different than current directory

sonar-runner-api/src/main/java/org/sonar/runner/api/Runner.java
sonar-runner-dist/src/main/java/org/sonar/runner/Conf.java
sonar-runner-dist/src/test/java/org/sonar/runner/ConfTest.java
sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties [new file with mode: 0644]
sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties [new file with mode: 0644]
sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties [new file with mode: 0644]

index 19a9506995f4428d6084f4dc84a7920b59110a30..b7583de0d290ac780c84be72fa6e99f6bd822330 100644 (file)
@@ -94,7 +94,7 @@ public abstract class Runner<T extends Runner> {
 
   private void initDefaultValues() {
     setDefaultValue(RunnerProperties.HOST_URL, "http://localhost:9000");
-    setDefaultValue(InternalProperties.RUNNER_APP, "SonarRunner");
+    setDefaultValue(InternalProperties.RUNNER_APP, "SonarQubeRunner");
     setDefaultValue(InternalProperties.RUNNER_APP_VERSION, RunnerVersion.version());
   }
 
index 2d68c02d98c88d1e6cfc59e360901a805216fbbb..c76176b79389a137b37691986c920b00a3cafda2 100644 (file)
@@ -25,6 +25,8 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Properties;
 
 class Conf {
@@ -32,6 +34,9 @@ class Conf {
   private static final String RUNNER_SETTINGS = "runner.settings";
   private static final String PROJECT_HOME = "project.home";
   private static final String PROJECT_SETTINGS = "project.settings";
+  private static final String PROPERTY_MODULES = "sonar.modules";
+  private static final String PROPERTY_PROJECT_BASEDIR = "sonar.projectBaseDir";
+  private static final String PROPERTY_PROJECT_CONFIG_FILE = "sonar.projectConfigFile";
 
   private final Cli cli;
 
@@ -45,13 +50,7 @@ class Conf {
     result.putAll(loadProjectProperties());
     result.putAll(System.getProperties());
     result.putAll(cli.properties());
-
-    if (result.containsKey(PROJECT_HOME)) {
-      // the real property of the Sonar Runner is "sonar.projectBaseDir"
-      String baseDir = result.getProperty(PROJECT_HOME);
-      result.remove(PROJECT_HOME);
-      result.put("sonar.projectBaseDir", baseDir);
-    }
+    result.remove(PROJECT_HOME);
     return result;
   }
 
@@ -66,15 +65,97 @@ class Conf {
   }
 
   private Properties loadProjectProperties() throws IOException {
-    File settingsFile = locatePropertiesFile(cli.properties(), PROJECT_HOME, "sonar-project.properties", PROJECT_SETTINGS);
-    if (settingsFile != null && settingsFile.isFile() && settingsFile.exists()) {
-      Logs.info("Project configuration file: " + settingsFile.getAbsolutePath());
-      return toProperties(settingsFile);
+    Properties cliProps = cli.properties();
+    File rootSettingsFile = locatePropertiesFile(cliProps, cliProps.containsKey(PROPERTY_PROJECT_BASEDIR) ? PROPERTY_PROJECT_BASEDIR : PROJECT_HOME, "sonar-project.properties",
+      PROJECT_SETTINGS);
+    if (rootSettingsFile != null && rootSettingsFile.isFile() && rootSettingsFile.exists()) {
+      Logs.info("Project configuration file: " + rootSettingsFile.getAbsolutePath());
+      Properties projectProps = new Properties();
+      Properties rootProps = toProperties(rootSettingsFile);
+      projectProps.putAll(rootProps);
+      initRootProjectBaseDir(cliProps, rootProps);
+      loadModulesProperties(rootProps, projectProps, "");
+      return projectProps;
     }
     Logs.info("Project configuration file: NONE");
     return new Properties();
   }
 
+  private void initRootProjectBaseDir(Properties cliProps, Properties rootProps) {
+    if (!cliProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
+      String baseDir = cliProps.getProperty(PROJECT_HOME);
+      rootProps.put(PROPERTY_PROJECT_BASEDIR, baseDir);
+    } else {
+      rootProps.put(PROPERTY_PROJECT_BASEDIR, cliProps.getProperty(PROPERTY_PROJECT_BASEDIR));
+    }
+  }
+
+  private void loadModulesProperties(Properties parentProps, Properties projectProps, String prefix) {
+    File parentBaseDir = new File(parentProps.getProperty(PROPERTY_PROJECT_BASEDIR));
+    if (parentProps.containsKey(PROPERTY_MODULES)) {
+      for (String module : getListFromProperty(parentProps, PROPERTY_MODULES)) {
+        Properties moduleProps = extractModuleProperties(module, parentProps);
+        moduleProps = loadChildConfigFile(parentBaseDir, moduleProps, module);
+
+        // the child project may have children as well
+        loadModulesProperties(moduleProps, projectProps, module + ".");
+        // and finally add this child properties to global props
+        merge(projectProps, prefix, module, moduleProps);
+      }
+    }
+
+  }
+
+  private void merge(Properties projectProps, String prefix, String module, Properties moduleProps) {
+    for (Map.Entry<Object, Object> entry : moduleProps.entrySet()) {
+      projectProps.put(prefix + module + "." + entry.getKey(), entry.getValue());
+    }
+  }
+
+  private Properties loadChildConfigFile(File parentBaseDir, Properties moduleProps, String moduleId) {
+    final File baseDir;
+    if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
+      baseDir = getFileFromPath(moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR), parentBaseDir);
+      setProjectBaseDir(baseDir, moduleProps, moduleId);
+      try {
+        if (!parentBaseDir.getCanonicalFile().equals(baseDir.getCanonicalFile())) {
+          tryToFindAndLoadPropsFile(baseDir, moduleProps, moduleId);
+        }
+      } catch (IOException e) {
+        throw new IllegalStateException("Error when resolving baseDir", e);
+      }
+    } else if (moduleProps.containsKey(PROPERTY_PROJECT_CONFIG_FILE)) {
+      baseDir = loadPropsFile(parentBaseDir, moduleProps, moduleId);
+      moduleProps.remove(PROPERTY_PROJECT_CONFIG_FILE);
+    } else {
+      baseDir = new File(parentBaseDir, moduleId);
+      setProjectBaseDir(baseDir, moduleProps, moduleId);
+      tryToFindAndLoadPropsFile(baseDir, moduleProps, moduleId);
+    }
+
+    return moduleProps;
+  }
+
+  private static void setProjectBaseDir(File baseDir, Properties childProps, String moduleId) {
+    if (!baseDir.isDirectory()) {
+      throw new IllegalStateException("The base directory of the module '" + moduleId + "' does not exist: " + baseDir.getAbsolutePath());
+    }
+    childProps.put(PROPERTY_PROJECT_BASEDIR, baseDir.getAbsolutePath());
+  }
+
+  protected static Properties extractModuleProperties(String module, Properties properties) {
+    Properties moduleProps = new Properties();
+    String propertyPrefix = module + ".";
+    int prefixLength = propertyPrefix.length();
+    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+      String key = (String) entry.getKey();
+      if (key.startsWith(propertyPrefix)) {
+        moduleProps.put(key.substring(prefixLength), entry.getValue());
+      }
+    }
+    return moduleProps;
+  }
+
   private File locatePropertiesFile(Properties props, String homeKey, String relativePathFromHome, String settingsKey) {
     File settingsFile = null;
     String runnerHome = props.getProperty(homeKey, "");
@@ -91,7 +172,7 @@ class Conf {
     return settingsFile;
   }
 
-  private static Properties toProperties(File file) throws IOException {
+  private static Properties toProperties(File file) {
     InputStream in = null;
     try {
       Properties properties = new Properties();
@@ -108,8 +189,75 @@ class Conf {
 
     } finally {
       if (in != null) {
-        in.close();
+        try {
+          in.close();
+        } catch (IOException e) {
+          // Ignore errors
+        }
+      }
+    }
+  }
+
+  /**
+   * @return baseDir
+   */
+  protected File loadPropsFile(File parentBaseDir, Properties moduleProps, String moduleId) {
+    File propertyFile = getFileFromPath(moduleProps.getProperty(PROPERTY_PROJECT_CONFIG_FILE), parentBaseDir);
+    if (propertyFile.isFile()) {
+      Properties propsFromFile = toProperties(propertyFile);
+      for (Entry<Object, Object> entry : propsFromFile.entrySet()) {
+        moduleProps.put(entry.getKey(), entry.getValue());
+      }
+      File baseDir = null;
+      if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
+        baseDir = getFileFromPath(moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR), propertyFile.getParentFile());
+      } else {
+        baseDir = propertyFile.getParentFile();
       }
+      setProjectBaseDir(baseDir, moduleProps, moduleId);
+      return baseDir;
+    } else {
+      throw new IllegalStateException("The properties file of the module '" + moduleId + "' does not exist: " + propertyFile.getAbsolutePath());
+    }
+  }
+
+  private void tryToFindAndLoadPropsFile(File baseDir, Properties moduleProps, String moduleId) {
+    File propertyFile = new File(baseDir, "sonar-project.properties");
+    if (propertyFile.isFile()) {
+      Properties propsFromFile = toProperties(propertyFile);
+      for (Entry<Object, Object> entry : propsFromFile.entrySet()) {
+        moduleProps.put(entry.getKey(), entry.getValue());
+      }
+      if (moduleProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
+        File overwrittenBaseDir = getFileFromPath(moduleProps.getProperty(PROPERTY_PROJECT_BASEDIR), propertyFile.getParentFile());
+        setProjectBaseDir(overwrittenBaseDir, moduleProps, moduleId);
+      }
+    }
+  }
+
+  /**
+   * Returns the file denoted by the given path, may this path be relative to "baseDir" or absolute.
+   */
+  protected static File getFileFromPath(String path, File baseDir) {
+    File propertyFile = new File(path.trim());
+    if (!propertyFile.isAbsolute()) {
+      propertyFile = new File(baseDir, propertyFile.getPath());
+    }
+    return propertyFile;
+  }
+
+  /**
+   * Transforms a comma-separated list String property in to a array of trimmed strings.
+   *
+   * This works even if they are separated by whitespace characters (space char, EOL, ...)
+   *
+   */
+  static String[] getListFromProperty(Properties properties, String key) {
+    String value = properties.getProperty(key, "");
+    String[] values = value.split(",");
+    for (int i = 0; i < values.length; i++) {
+      values[i] = values[i].trim();
     }
+    return values;
   }
 }
index d9ad17d8f42c87e8be87754a55b4ef51c7e82d28..323be3babab12cac05b748370b4e161b25592403 100644 (file)
@@ -20,7 +20,9 @@
 package org.sonar.runner;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
 
 import java.io.File;
 import java.util.Properties;
@@ -31,6 +33,9 @@ import static org.mockito.Mockito.when;
 
 public class ConfTest {
 
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
   Properties args = new Properties();
   Cli cli = mock(Cli.class);
   Conf conf = new Conf(cli);
@@ -61,20 +66,41 @@ public class ConfTest {
     assertThat(conf.properties().get("sonar.prop")).isEqualTo("otherValue");
   }
 
-  // @Test
-  // public void shouldLoadCompleteConfiguration() throws Exception {
-  // File runnerHome = new File(getClass().getResource("/org/sonar/runner/MainTest/shouldLoadCompleteConfiguration/runner").toURI());
-  // File projectHome = new File(getClass().getResource("/org/sonar/runner/MainTest/shouldLoadCompleteConfiguration/project").toURI());
-  // Main main = new Main();
-  // Properties args = main.parseArguments(new String[] {
-  // "-D", "runner.home=" + runnerHome.getCanonicalPath(),
-  // "-D", "project.home=" + projectHome.getCanonicalPath()
-  // });
-  // main.loadProperties(args);
-  //
-  // assertThat(main.projectProperties.getProperty("project.prop")).isEqualTo("foo");
-  // assertThat(main.projectProperties.getProperty("overridden.prop")).isEqualTo("project scope");
-  // assertThat(main.globalProperties.getProperty("global.prop")).isEqualTo("jdbc:mysql:localhost/sonar");
-  // }
+  @Test
+  public void shouldLoadCompleteConfiguration() throws Exception {
+    File runnerHome = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/runner").toURI());
+    File projectHome = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/project").toURI());
+    args.setProperty("runner.home", runnerHome.getCanonicalPath());
+    args.setProperty("project.home", projectHome.getCanonicalPath());
+
+    Properties properties = conf.properties();
+
+    assertThat(properties.getProperty("project.prop")).isEqualTo("foo");
+    assertThat(properties.getProperty("overridden.prop")).isEqualTo("project scope");
+    assertThat(properties.getProperty("global.prop")).isEqualTo("jdbc:mysql:localhost/sonar");
+  }
+
+  @Test
+  public void shouldLoadModuleConfiguration() throws Exception {
+    File projectHome = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project").toURI());
+    args.setProperty("project.home", projectHome.getCanonicalPath());
+
+    Properties properties = conf.properties();
+
+    assertThat(properties.getProperty("module1.sonar.projectName")).isEqualTo("Module 1");
+    assertThat(properties.getProperty("module2.sonar.projectName")).isEqualTo("Module 2");
+  }
+
+  @Test
+  public void shouldSupportSettingBaseDirFromCli() throws Exception {
+    File projectHome = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project").toURI());
+    args.setProperty("project.home", temp.newFolder().getCanonicalPath());
+    args.setProperty("sonar.projectBaseDir", projectHome.getCanonicalPath());
+
+    Properties properties = conf.properties();
+
+    assertThat(properties.getProperty("module1.sonar.projectName")).isEqualTo("Module 1");
+    assertThat(properties.getProperty("module2.sonar.projectName")).isEqualTo("Module 2");
+  }
 
 }
diff --git a/sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties b/sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties
new file mode 100644 (file)
index 0000000..6803263
--- /dev/null
@@ -0,0 +1 @@
+sonar.projectName=Module 1
diff --git a/sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties b/sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties
new file mode 100644 (file)
index 0000000..c12fad8
--- /dev/null
@@ -0,0 +1 @@
+sonar.projectName=Module 2
diff --git a/sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties b/sonar-runner-dist/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties
new file mode 100644 (file)
index 0000000..835124c
--- /dev/null
@@ -0,0 +1 @@
+sonar.modules=module1,module2