]> source.dussan.org Git - sonar-scanner-cli.git/commitdiff
Update groupId, artifactId and packages
authorJulien HENRY <julien.henry@sonarsource.com>
Mon, 11 Jan 2016 15:14:39 +0000 (16:14 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Mon, 11 Jan 2016 15:14:39 +0000 (16:14 +0100)
79 files changed:
pom.xml
src/main/assembly/bin/sonar-runner
src/main/assembly/bin/sonar-runner.bat
src/main/java/org/sonar/runner/cli/Cli.java [deleted file]
src/main/java/org/sonar/runner/cli/Conf.java [deleted file]
src/main/java/org/sonar/runner/cli/Exit.java [deleted file]
src/main/java/org/sonar/runner/cli/Logs.java [deleted file]
src/main/java/org/sonar/runner/cli/Main.java [deleted file]
src/main/java/org/sonar/runner/cli/RunnerFactory.java [deleted file]
src/main/java/org/sonar/runner/cli/Shutdown.java [deleted file]
src/main/java/org/sonar/runner/cli/Stats.java [deleted file]
src/main/java/org/sonar/runner/cli/SystemInfo.java [deleted file]
src/main/java/org/sonar/runner/cli/package-info.java [deleted file]
src/main/java/org/sonarsource/scanner/cli/Cli.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/Conf.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/Exit.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/Logs.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/Main.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/RunnerFactory.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/Shutdown.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/Stats.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/SystemInfo.java [new file with mode: 0644]
src/main/java/org/sonarsource/scanner/cli/package-info.java [new file with mode: 0644]
src/test/java/org/sonar/runner/cli/CliTest.java [deleted file]
src/test/java/org/sonar/runner/cli/ConfTest.java [deleted file]
src/test/java/org/sonar/runner/cli/LogsTest.java [deleted file]
src/test/java/org/sonar/runner/cli/MainTest.java [deleted file]
src/test/java/org/sonar/runner/cli/RunnerFactoryTest.java [deleted file]
src/test/java/org/sonar/runner/cli/ShutdownTest.java [deleted file]
src/test/java/org/sonar/runner/cli/StatsTest.java [deleted file]
src/test/java/org/sonar/runner/cli/SystemInfoTest.java [deleted file]
src/test/java/org/sonarsource/scanner/cli/CliTest.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/ConfTest.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/LogsTest.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/MainTest.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/RunnerFactoryTest.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/ShutdownTest.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/StatsTest.java [new file with mode: 0644]
src/test/java/org/sonarsource/scanner/cli/SystemInfoTest.java [new file with mode: 0644]
src/test/resources/org/sonar/runner/ConfTest/emptyModules/project/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/project/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/runner/conf/sonar-runner.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module2.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_1/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_2/Sample.js [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_3/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByHome/conf/sonar-runner.properties [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module111/placeholder.txt [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module112/placeholder.txt [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module12/placeholder.txt [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module21/placeholder.txt [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module22/placeholder.txt [deleted file]
src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/sonar-project.properties [deleted file]
src/test/resources/org/sonar/runner/RunnerTest/shouldInitDirs/fake.txt [deleted file]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/emptyModules/project/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadCompleteConfiguration/project/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadCompleteConfiguration/runner/conf/sonar-runner.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module2.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_1/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_2/Sample.js [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_3/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadRunnerSettingsByHome/conf/sonar-runner.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module111/placeholder.txt [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module112/placeholder.txt [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module12/placeholder.txt [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module21/placeholder.txt [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module22/placeholder.txt [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/sonar-project.properties [new file with mode: 0644]
src/test/resources/org/sonarsource/scanner/cli/RunnerTest/shouldInitDirs/fake.txt [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index f850bbe11c6301bbffbce9f13c8938a3d3a3be57..cff6932dfe0fd345c73a17130bb295b3aaca5bf8 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -6,8 +6,8 @@
     <version>23</version>
   </parent>
 
-  <groupId>org.sonarsource.scanner</groupId>
-  <artifactId>sonar-scanner</artifactId>
+  <groupId>org.sonarsource.scanner.cli</groupId>
+  <artifactId>sonar-scanner-cli</artifactId>
   <version>2.5-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>SonarQube Scanner</name>
index ec2f4268d1b5986afc05ed9288de592534a93b76..3d2b09298336efb0b5e81af8c0aa1d391df39ebc 100755 (executable)
@@ -80,7 +80,7 @@ if [ -z "$SONAR_RUNNER_HOME" ] ; then
 fi
 
 # check that the SONAR_RUNNER_HOME has been correctly set
-if [ ! -f "$SONAR_RUNNER_HOME/lib/sonar-scanner-${project.version}.jar" ] ; then
+if [ ! -f "$SONAR_RUNNER_HOME/lib/sonar-scanner-cli-${project.version}.jar" ] ; then
   echo '$SONAR_RUNNER_HOME' does not point to a valid installation directory: $SONAR_RUNNER_HOME
   exit 1
 fi
@@ -92,7 +92,7 @@ else
   JAVA_CMD="`which java`"
 fi
 
-JAR_FILE="${SONAR_RUNNER_HOME}"/lib/sonar-scanner-${project.version}.jar
+JAR_FILE="${SONAR_RUNNER_HOME}"/lib/sonar-scanner-cli-${project.version}.jar
 PROJECT_HOME=`pwd`
 
 #echo "Info: Using sonar-runner at $SONAR_RUNNER_HOME"
@@ -106,5 +106,5 @@ exec "$JAVA_CMD" \
   -classpath  $JAR_FILE \
   "-Drunner.home=\${SONAR_RUNNER_HOME}" \
   "-Dproject.home=\${PROJECT_HOME}" \
-  org.sonar.runner.cli.Main "$@"
+  org.sonarsource.scanner.cli.Main "$@"
 
index 72d054bbc38ee4802d84938fcc059cd33865d764..32b3e83067c0d4b8b9108ee05817012fe9b2339b 100644 (file)
@@ -58,7 +58,7 @@ goto run
 if "%SONAR_RUNNER_HOME:~-1%"=="\" set SONAR_RUNNER_HOME=%SONAR_RUNNER_HOME:~0,-1%
 
 @REM Check if the provided SONAR_RUNNER_HOME is a valid install dir
-IF EXIST "%SONAR_RUNNER_HOME%\lib\sonar-scanner-${project.version}.jar" goto run
+IF EXIST "%SONAR_RUNNER_HOME%\lib\sonar-scanner-cli-${project.version}.jar" goto run
 
 echo.
 echo ERROR: SONAR_RUNNER_HOME exists but does not point to a valid install
@@ -74,7 +74,7 @@ echo %SONAR_RUNNER_HOME%
 
 set PROJECT_HOME=%CD%
 
-%JAVA_EXEC% -Djava.awt.headless=true %SONAR_RUNNER_OPTS% -cp "%SONAR_RUNNER_HOME%\lib\sonar-scanner-${project.version}.jar" "-Drunner.home=%SONAR_RUNNER_HOME%" "-Dproject.home=%PROJECT_HOME%" org.sonar.runner.cli.Main %*
+%JAVA_EXEC% -Djava.awt.headless=true %SONAR_RUNNER_OPTS% -cp "%SONAR_RUNNER_HOME%\lib\sonar-scanner-cli-${project.version}.jar" "-Drunner.home=%SONAR_RUNNER_HOME%" "-Dproject.home=%PROJECT_HOME%" org.sonarsource.scanner.cli.Main %*
 if ERRORLEVEL 1 goto error
 goto end
 
diff --git a/src/main/java/org/sonar/runner/cli/Cli.java b/src/main/java/org/sonar/runner/cli/Cli.java
deleted file mode 100644 (file)
index f95302d..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import java.util.Properties;
-import org.sonar.runner.api.RunnerProperties;
-
-class Cli {
-
-  private boolean debugMode = false;
-  private boolean displayVersionOnly = false;
-  private boolean displayStackTrace = false;
-  private boolean interactive = false;
-  private final Properties props = new Properties();
-  private final Exit exit;
-  private final Logs logger;
-
-  public Cli(Exit exit, Logs logger) {
-    this.exit = exit;
-    this.logger = logger;
-  }
-
-  boolean isDebugMode() {
-    return debugMode;
-  }
-
-  boolean isDisplayVersionOnly() {
-    return displayVersionOnly;
-  }
-
-  boolean isDisplayStackTrace() {
-    return displayStackTrace;
-  }
-
-  boolean isInteractive() {
-    return interactive;
-  }
-
-  Properties properties() {
-    return props;
-  }
-
-  Cli parse(String[] args) {
-    reset();
-    props.putAll(System.getProperties());
-    for (int i = 0; i < args.length; i++) {
-      String arg = args[i];
-      if (i == 0 && !arg.startsWith("-")) {
-        props.setProperty(RunnerProperties.TASK, arg);
-
-      } else if ("-h".equals(arg) || "--help".equals(arg)) {
-        printUsage();
-
-      } else if ("-v".equals(arg) || "--version".equals(arg)) {
-        displayVersionOnly = true;
-
-      } else if ("-e".equals(arg) || "--errors".equals(arg)) {
-        displayStackTrace = true;
-        logger.setDisplayStackTrace(true);
-
-      } else if ("-X".equals(arg) || "--debug".equals(arg)) {
-        props.setProperty("sonar.verbose", "true");
-        displayStackTrace = true;
-        debugMode = true;
-        logger.setDebugEnabled(true);
-        logger.setDisplayStackTrace(true);
-
-      } else if ("-D".equals(arg) || "--define".equals(arg)) {
-        i++;
-        if (i >= args.length) {
-          printError("Missing argument for option --define");
-        }
-        arg = args[i];
-        appendPropertyTo(arg, props);
-
-      } else if (arg.startsWith("-D")) {
-        arg = arg.substring(2);
-        appendPropertyTo(arg, props);
-
-      } else if ("-i".equals(arg) || "--interactive".equals(arg)) {
-        interactive = true;
-
-      } else {
-        printError("Unrecognized option: " + arg);
-      }
-    }
-
-    return this;
-  }
-
-  public void verify() {
-    if ("fork".equals(props.getProperty("sonarRunner.mode")) && isInteractive()) {
-      printError("Cannot run interactively in fork mode.");
-    }
-  }
-
-  private void reset() {
-    props.clear();
-    debugMode = false;
-    displayStackTrace = false;
-    displayVersionOnly = false;
-  }
-
-  private static void appendPropertyTo(String arg, Properties props) {
-    final String key, value;
-    int j = arg.indexOf('=');
-    if (j == -1) {
-      key = arg;
-      value = "true";
-    } else {
-      key = arg.substring(0, j);
-      value = arg.substring(j + 1);
-    }
-    props.setProperty(key, value);
-  }
-
-  private void printError(String message) {
-    logger.error(message);
-    printUsage();
-  }
-
-  private void printUsage() {
-    logger.info("");
-    logger.info("usage: sonar-runner [options]");
-    logger.info("");
-    logger.info("Options:");
-    logger.info(" -D,--define <arg>     Define property");
-    logger.info(" -e,--errors           Produce execution error messages");
-    logger.info(" -h,--help             Display help information");
-    logger.info(" -v,--version          Display version information");
-    logger.info(" -X,--debug            Produce execution debug output");
-    logger.info(" -i,--interactive      Run interactively");
-    exit.exit(Exit.SUCCESS);
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/Conf.java b/src/main/java/org/sonar/runner/cli/Conf.java
deleted file mode 100644 (file)
index 150e573..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-class Conf {
-  private static final String RUNNER_HOME = "runner.home";
-  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 static final String SONAR_PROJECT_PROPERTIES_FILENAME = "sonar-project.properties";
-
-  private final Cli cli;
-  private final Logs logger;
-
-  Conf(Cli cli, Logs logger) {
-    this.cli = cli;
-    this.logger = logger;
-  }
-
-  Properties properties() throws IOException {
-    Properties result = new Properties();
-    result.putAll(loadGlobalProperties());
-    result.putAll(loadProjectProperties());
-    result.putAll(System.getProperties());
-    result.putAll(cli.properties());
-    result.remove(PROJECT_HOME);
-    return result;
-  }
-
-  private Properties loadGlobalProperties() throws IOException {
-    File settingsFile = locatePropertiesFile(cli.properties(), RUNNER_HOME, "conf/sonar-runner.properties", RUNNER_SETTINGS);
-    if (settingsFile != null && settingsFile.isFile() && settingsFile.exists()) {
-      logger.info("Runner configuration file: " + settingsFile.getAbsolutePath());
-      return toProperties(settingsFile);
-    }
-    logger.info("Runner configuration file: NONE");
-    return new Properties();
-  }
-
-  private Properties loadProjectProperties() throws IOException {
-    Properties cliProps = cli.properties();
-    File rootSettingsFile = locatePropertiesFile(cliProps, cliProps.containsKey(PROPERTY_PROJECT_BASEDIR) ? PROPERTY_PROJECT_BASEDIR : PROJECT_HOME,
-      SONAR_PROJECT_PROPERTIES_FILENAME,
-      PROJECT_SETTINGS);
-    if (rootSettingsFile != null && rootSettingsFile.isFile() && rootSettingsFile.exists()) {
-      logger.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;
-    }
-    logger.info("Project configuration file: NONE");
-    return new Properties();
-  }
-
-  private static 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, prefix + module + ".");
-        // and finally add this child properties to global props
-        merge(projectProps, prefix, module, moduleProps);
-      }
-    }
-
-  }
-
-  private static 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);
-      setProjectBaseDir(baseDir, 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(MessageFormat.format("The base directory of the module ''{0}'' does not exist: {1}", moduleId, 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 static File locatePropertiesFile(Properties props, String homeKey, String relativePathFromHome, String settingsKey) {
-    File settingsFile = null;
-    String runnerHome = props.getProperty(homeKey, "");
-    if (!"".equals(runnerHome)) {
-      settingsFile = new File(runnerHome, relativePathFromHome);
-    }
-
-    if (settingsFile == null || !settingsFile.exists()) {
-      String settingsPath = props.getProperty(settingsKey, "");
-      if (!"".equals(settingsPath)) {
-        settingsFile = new File(settingsPath);
-      }
-    }
-    return settingsFile;
-  }
-
-  private static Properties toProperties(File file) {
-    InputStream in = null;
-    try {
-      Properties properties = new Properties();
-      in = new FileInputStream(file);
-      properties.load(in);
-      // Trim properties
-      for (String propKey : properties.stringPropertyNames()) {
-        properties.setProperty(propKey, properties.getProperty(propKey).trim());
-      }
-      return properties;
-
-    } catch (Exception e) {
-      throw new IllegalStateException("Fail to load file: " + file.getAbsolutePath(), e);
-
-    } finally {
-      if (in != null) {
-        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 static void tryToFindAndLoadPropsFile(File baseDir, Properties moduleProps, String moduleId) {
-    File propertyFile = new File(baseDir, SONAR_PROJECT_PROPERTIES_FILENAME);
-    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, "").trim();
-    if (value.isEmpty()) {
-      return new String[0];
-    }
-    String[] values = value.split(",");
-    List<String> trimmedValues = new ArrayList<>();
-    for (int i = 0; i < values.length; i++) {
-      String trimmedValue = values[i].trim();
-      if (!trimmedValue.isEmpty()) {
-        trimmedValues.add(trimmedValue);
-      }
-    }
-    return trimmedValues.toArray(new String[trimmedValues.size()]);
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/Exit.java b/src/main/java/org/sonar/runner/cli/Exit.java
deleted file mode 100644 (file)
index 9c92b6b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-class Exit {
-  static final int SUCCESS = 0;
-  static final int ERROR = 1;
-
-  void exit(int status) {
-    System.exit(status);
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/Logs.java b/src/main/java/org/sonar/runner/cli/Logs.java
deleted file mode 100644 (file)
index 8df9b9b..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import java.io.PrintStream;
-
-public class Logs {
-  private boolean debugEnabled = false;
-  private boolean displayStackTrace = false;
-  private PrintStream stdOut;
-  private PrintStream stdErr;
-
-  public Logs(PrintStream stdOut, PrintStream stdErr) {
-    this.stdErr = stdErr;
-    this.stdOut = stdOut;
-  }
-
-  public void setDebugEnabled(boolean debugEnabled) {
-    this.debugEnabled = debugEnabled;
-  }
-
-  public void setDisplayStackTrace(boolean displayStackTrace) {
-    this.displayStackTrace = displayStackTrace;
-  }
-
-  public boolean isDebugEnabled() {
-    return debugEnabled;
-  }
-
-  public void debug(String message) {
-    if (isDebugEnabled()) {
-      stdOut.println("DEBUG: " + message);
-    }
-  }
-
-  public void info(String message) {
-    stdOut.println("INFO: " + message);
-  }
-
-  public void warn(String message) {
-    stdOut.println("WARN: " + message);
-  }
-
-  public void error(String message) {
-    stdErr.println("ERROR: " + message);
-  }
-
-  public void error(String message, Throwable t) {
-    stdErr.println("ERROR: " + message);
-    if (t != null && displayStackTrace) {
-      t.printStackTrace(stdErr);
-    }
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/Main.java b/src/main/java/org/sonar/runner/cli/Main.java
deleted file mode 100644 (file)
index 848b64e..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Properties;
-import org.sonar.runner.api.EmbeddedRunner;
-
-/**
- * Arguments :
- * <ul>
- * <li>runner.home: optional path to runner home (root directory with sub-directories bin, lib and conf)</li>
- * <li>runner.settings: optional path to runner global settings, usually ${runner.home}/conf/sonar-runner.properties.
- * This property is used only if ${runner.home} is not defined</li>
- * <li>project.home: path to project root directory. If not set, then it's supposed to be the directory where the runner is executed</li>
- * <li>project.settings: optional path to project settings. Default value is ${project.home}/sonar-project.properties.</li>
- * </ul>
- *
- * @since 1.0
- */
-public class Main {
-
-  private final Shutdown shutdown;
-  private final Cli cli;
-  private final Conf conf;
-  private EmbeddedRunner runner;
-  private BufferedReader inputReader;
-  private RunnerFactory runnerFactory;
-  private Logs logger;
-
-  Main(Shutdown shutdown, Cli cli, Conf conf, RunnerFactory runnerFactory, Logs logger) {
-    this.shutdown = shutdown;
-    this.cli = cli;
-    this.conf = conf;
-    this.runnerFactory = runnerFactory;
-    this.logger = logger;
-  }
-
-  public static void main(String[] args) {
-    Exit exit = new Exit();
-    Logs logs = new Logs(System.out, System.err);
-    Cli cli = new Cli(exit, logs).parse(args);
-    cli.verify();
-    Shutdown shutdown = new Shutdown(exit, cli.isInteractive());
-    Main main = new Main(shutdown, cli, new Conf(cli, logs), new RunnerFactory(logs), logs);
-    main.execute();
-  }
-
-  void execute() {
-    Stats stats = new Stats(logger).start();
-
-    try {
-      Properties p = conf.properties();
-      init(p);
-      runner.start();
-
-      if (cli.isInteractive()) {
-        interactiveLoop(p);
-      } else {
-        runAnalysis(stats, p);
-      }
-    } catch (Exception e) {
-      displayExecutionResult(stats, "FAILURE");
-      showError("Error during Sonar runner execution", e, cli.isDisplayStackTrace());
-      shutdown.exit(Exit.ERROR);
-    }
-
-    runner.stop();
-    shutdown.exit(Exit.SUCCESS);
-  }
-
-  private void interactiveLoop(Properties p) throws IOException {
-    do {
-      Stats stats = new Stats(logger).start();
-      try {
-        runAnalysis(stats, p);
-      } catch (Exception e) {
-        displayExecutionResult(stats, "FAILURE");
-        showError("Error during Sonar runner execution", e, cli.isDisplayStackTrace());
-      }
-    } while (waitForUser());
-  }
-
-  private void init(Properties p) throws IOException {
-    SystemInfo.print(logger);
-    if (cli.isDisplayVersionOnly()) {
-      shutdown.exit(Exit.SUCCESS);
-    }
-
-    if (cli.isDisplayStackTrace()) {
-      logger.info("Error stacktraces are turned on.");
-    }
-
-    runner = runnerFactory.create(p);
-  }
-
-  private void runAnalysis(Stats stats, Properties p) {
-    runner.runAnalysis(p);
-    displayExecutionResult(stats, "SUCCESS");
-  }
-
-  private boolean waitForUser() throws IOException {
-    if (inputReader == null) {
-      inputReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
-    }
-
-    shutdown.signalReady(true);
-    if (shutdown.shouldExit()) {
-      // exit before displaying message
-      return false;
-    }
-
-    System.out.println("");
-    System.out.println("<Press enter to restart analysis or Ctrl+C to exit the interactive mode>");
-    String line = inputReader.readLine();
-    shutdown.signalReady(false);
-
-    return line != null;
-  }
-
-  // Visible for testing
-  void setInputReader(BufferedReader inputReader) {
-    this.inputReader = inputReader;
-  }
-
-  private void displayExecutionResult(Stats stats, String resultMsg) {
-    logger.info("------------------------------------------------------------------------");
-    logger.info("EXECUTION " + resultMsg);
-    logger.info("------------------------------------------------------------------------");
-    stats.stop();
-    logger.info("------------------------------------------------------------------------");
-  }
-
-  private void showError(String message, Throwable e, boolean showStackTrace) {
-    if (showStackTrace) {
-      logger.error(message, e);
-      if (!cli.isDebugMode()) {
-        logger.error("");
-        suggestDebugMode();
-      }
-    } else {
-      logger.error(message);
-      if (e != null) {
-        logger.error(e.getMessage());
-        String previousMsg = "";
-        for (Throwable cause = e.getCause(); cause != null
-          && cause.getMessage() != null
-          && !cause.getMessage().equals(previousMsg); cause = cause.getCause()) {
-          logger.error("Caused by: " + cause.getMessage());
-          previousMsg = cause.getMessage();
-        }
-      }
-      logger.error("");
-      logger.error("To see the full stack trace of the errors, re-run SonarQube Runner with the -e switch.");
-      if (!cli.isDebugMode()) {
-        suggestDebugMode();
-      }
-    }
-  }
-
-  private void suggestDebugMode() {
-    logger.error("Re-run SonarQube Runner using the -X switch to enable full debug logging.");
-  }
-
-}
diff --git a/src/main/java/org/sonar/runner/cli/RunnerFactory.java b/src/main/java/org/sonar/runner/cli/RunnerFactory.java
deleted file mode 100644 (file)
index fcd0b65..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import java.util.Properties;
-import org.sonar.runner.api.EmbeddedRunner;
-import org.sonar.runner.api.LogOutput;
-
-class RunnerFactory {
-
-  private final Logs logger;
-
-  public RunnerFactory(Logs logger) {
-    this.logger = logger;
-  }
-
-  EmbeddedRunner create(Properties props) {
-    return EmbeddedRunner.create(new DefaultLogOutput()).addGlobalProperties(props);
-  }
-
-  class DefaultLogOutput implements LogOutput {
-    @Override
-    public void log(String formattedMessage, Level level) {
-      switch (level) {
-        case TRACE:
-        case DEBUG:
-          logger.debug(formattedMessage);
-          break;
-        case ERROR:
-          logger.error(formattedMessage);
-          break;
-        case INFO:
-        case WARN:
-        default:
-          logger.info(formattedMessage);
-      }
-    }
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/Shutdown.java b/src/main/java/org/sonar/runner/cli/Shutdown.java
deleted file mode 100644 (file)
index c598486..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-class Shutdown {
-  static final int SUCCESS = 0;
-  static final int ERROR = 1;
-  private static final long DEFAULT_MAX_WAIT = 10_000;
-
-  private long maxWait;
-  ShutdownHook hook = new ShutdownHook();
-  private boolean isReady = false;
-  private boolean exiting = false;
-  private Object lock = new Object();
-  private Exit exit;
-
-  Shutdown(Exit exit, boolean isInteractive) {
-    this(exit, isInteractive, DEFAULT_MAX_WAIT);
-  }
-
-  Shutdown(Exit exit, boolean isInteractive, long maxWait) {
-    this.maxWait = maxWait;
-    this.exit = exit;
-    if (isInteractive) {
-      Runtime.getRuntime().addShutdownHook(hook);
-    }
-  }
-
-  void exit(int status) {
-    synchronized (lock) {
-      signalReady(true);
-    }
-    exit.exit(status);
-  }
-
-  void signalReady(boolean ready) {
-    synchronized (lock) {
-      this.isReady = ready;
-      lock.notifyAll();
-    }
-  }
-
-  boolean shouldExit() {
-    synchronized (lock) {
-      return exiting;
-    }
-  }
-
-  class ShutdownHook extends Thread {
-    private ShutdownHook() {
-      this.setName("shutdown-hook");
-    }
-
-    @Override
-    public void run() {
-      long startTime = System.currentTimeMillis();
-      synchronized (lock) {
-        exiting = true;
-
-        while (!isReady) {
-          long waitTime = startTime + maxWait - System.currentTimeMillis();
-          if (waitTime <= 0) {
-            break;
-          }
-
-          try {
-            lock.wait(waitTime);
-          } catch (InterruptedException e) {
-            // continue
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/Stats.java b/src/main/java/org/sonar/runner/cli/Stats.java
deleted file mode 100644 (file)
index 6b3ca60..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-class Stats {
-  private final Logs logger;
-  private long startTime;
-
-  Stats(Logs logger) {
-    this.logger = logger;
-  }
-
-  Stats start() {
-    startTime = System.currentTimeMillis();
-    return this;
-  }
-
-  Stats stop() {
-    long stopTime = System.currentTimeMillis() - startTime;
-    logger.info("Total time: " + formatTime(stopTime));
-
-    System.gc();
-    Runtime r = Runtime.getRuntime();
-    long mb = 1024L * 1024;
-    logger.info("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M");
-
-    return this;
-  }
-
-  static String formatTime(long time) {
-    long h = time / (60 * 60 * 1000);
-    long m = (time - h * 60 * 60 * 1000) / (60 * 1000);
-    long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000;
-    long ms = time % 1000;
-    final String format;
-    if (h > 0) {
-      format = "%1$d:%2$02d:%3$02d.%4$03ds";
-    } else if (m > 0) {
-      format = "%2$d:%3$02d.%4$03ds";
-    } else {
-      format = "%3$d.%4$03ds";
-    }
-    return String.format(format, h, m, s, ms);
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/SystemInfo.java b/src/main/java/org/sonar/runner/cli/SystemInfo.java
deleted file mode 100644 (file)
index de3c82f..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import org.sonar.runner.api.RunnerVersion;
-
-class SystemInfo {
-  private static System2 system = new System2();
-
-  private SystemInfo() {
-  }
-
-  static void setSystem(System2 system) {
-    SystemInfo.system = system;
-  }
-
-  static void print(Logs logger) {
-    logger.info("SonarQube Runner " + RunnerVersion.version());
-    logger.info(java());
-    logger.info(os());
-    String runnerOpts = system.getenv("SONAR_RUNNER_OPTS");
-    if (runnerOpts != null) {
-      logger.info("SONAR_RUNNER_OPTS=" + runnerOpts);
-    }
-  }
-
-  static String java() {
-    StringBuilder sb = new StringBuilder();
-    sb
-      .append("Java ")
-      .append(system.getProperty("java.version"))
-      .append(" ")
-      .append(system.getProperty("java.vendor"));
-    String bits = system.getProperty("sun.arch.data.model");
-    if ("32".equals(bits) || "64".equals(bits)) {
-      sb.append(" (").append(bits).append("-bit)");
-    }
-    return sb.toString();
-  }
-
-  static String os() {
-    StringBuilder sb = new StringBuilder();
-    sb
-      .append(system.getProperty("os.name"))
-      .append(" ")
-      .append(system.getProperty("os.version"))
-      .append(" ")
-      .append(system.getProperty("os.arch"));
-    return sb.toString();
-  }
-
-  static class System2 {
-    String getProperty(String key) {
-      return System.getProperty(key);
-    }
-
-    String getenv(String key) {
-      return System.getenv(key);
-    }
-  }
-}
diff --git a/src/main/java/org/sonar/runner/cli/package-info.java b/src/main/java/org/sonar/runner/cli/package-info.java
deleted file mode 100644 (file)
index 55dfaf6..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-@ParametersAreNonnullByDefault
-package org.sonar.runner.cli;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
diff --git a/src/main/java/org/sonarsource/scanner/cli/Cli.java b/src/main/java/org/sonarsource/scanner/cli/Cli.java
new file mode 100644 (file)
index 0000000..54b55bd
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import java.util.Properties;
+import org.sonar.runner.api.RunnerProperties;
+
+class Cli {
+
+  private boolean debugMode = false;
+  private boolean displayVersionOnly = false;
+  private boolean displayStackTrace = false;
+  private boolean interactive = false;
+  private final Properties props = new Properties();
+  private final Exit exit;
+  private final Logs logger;
+
+  public Cli(Exit exit, Logs logger) {
+    this.exit = exit;
+    this.logger = logger;
+  }
+
+  boolean isDebugMode() {
+    return debugMode;
+  }
+
+  boolean isDisplayVersionOnly() {
+    return displayVersionOnly;
+  }
+
+  boolean isDisplayStackTrace() {
+    return displayStackTrace;
+  }
+
+  boolean isInteractive() {
+    return interactive;
+  }
+
+  Properties properties() {
+    return props;
+  }
+
+  Cli parse(String[] args) {
+    reset();
+    props.putAll(System.getProperties());
+    for (int i = 0; i < args.length; i++) {
+      String arg = args[i];
+      if (i == 0 && !arg.startsWith("-")) {
+        props.setProperty(RunnerProperties.TASK, arg);
+
+      } else if ("-h".equals(arg) || "--help".equals(arg)) {
+        printUsage();
+
+      } else if ("-v".equals(arg) || "--version".equals(arg)) {
+        displayVersionOnly = true;
+
+      } else if ("-e".equals(arg) || "--errors".equals(arg)) {
+        displayStackTrace = true;
+        logger.setDisplayStackTrace(true);
+
+      } else if ("-X".equals(arg) || "--debug".equals(arg)) {
+        props.setProperty("sonar.verbose", "true");
+        displayStackTrace = true;
+        debugMode = true;
+        logger.setDebugEnabled(true);
+        logger.setDisplayStackTrace(true);
+
+      } else if ("-D".equals(arg) || "--define".equals(arg)) {
+        i++;
+        if (i >= args.length) {
+          printError("Missing argument for option --define");
+        }
+        arg = args[i];
+        appendPropertyTo(arg, props);
+
+      } else if (arg.startsWith("-D")) {
+        arg = arg.substring(2);
+        appendPropertyTo(arg, props);
+
+      } else if ("-i".equals(arg) || "--interactive".equals(arg)) {
+        interactive = true;
+
+      } else {
+        printError("Unrecognized option: " + arg);
+      }
+    }
+
+    return this;
+  }
+
+  public void verify() {
+    if ("fork".equals(props.getProperty("sonarRunner.mode")) && isInteractive()) {
+      printError("Cannot run interactively in fork mode.");
+    }
+  }
+
+  private void reset() {
+    props.clear();
+    debugMode = false;
+    displayStackTrace = false;
+    displayVersionOnly = false;
+  }
+
+  private static void appendPropertyTo(String arg, Properties props) {
+    final String key, value;
+    int j = arg.indexOf('=');
+    if (j == -1) {
+      key = arg;
+      value = "true";
+    } else {
+      key = arg.substring(0, j);
+      value = arg.substring(j + 1);
+    }
+    props.setProperty(key, value);
+  }
+
+  private void printError(String message) {
+    logger.error(message);
+    printUsage();
+  }
+
+  private void printUsage() {
+    logger.info("");
+    logger.info("usage: sonar-runner [options]");
+    logger.info("");
+    logger.info("Options:");
+    logger.info(" -D,--define <arg>     Define property");
+    logger.info(" -e,--errors           Produce execution error messages");
+    logger.info(" -h,--help             Display help information");
+    logger.info(" -v,--version          Display version information");
+    logger.info(" -X,--debug            Produce execution debug output");
+    logger.info(" -i,--interactive      Run interactively");
+    exit.exit(Exit.SUCCESS);
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/Conf.java b/src/main/java/org/sonarsource/scanner/cli/Conf.java
new file mode 100644 (file)
index 0000000..7d8cd15
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+class Conf {
+  private static final String RUNNER_HOME = "runner.home";
+  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 static final String SONAR_PROJECT_PROPERTIES_FILENAME = "sonar-project.properties";
+
+  private final Cli cli;
+  private final Logs logger;
+
+  Conf(Cli cli, Logs logger) {
+    this.cli = cli;
+    this.logger = logger;
+  }
+
+  Properties properties() throws IOException {
+    Properties result = new Properties();
+    result.putAll(loadGlobalProperties());
+    result.putAll(loadProjectProperties());
+    result.putAll(System.getProperties());
+    result.putAll(cli.properties());
+    result.remove(PROJECT_HOME);
+    return result;
+  }
+
+  private Properties loadGlobalProperties() throws IOException {
+    File settingsFile = locatePropertiesFile(cli.properties(), RUNNER_HOME, "conf/sonar-runner.properties", RUNNER_SETTINGS);
+    if (settingsFile != null && settingsFile.isFile() && settingsFile.exists()) {
+      logger.info("Runner configuration file: " + settingsFile.getAbsolutePath());
+      return toProperties(settingsFile);
+    }
+    logger.info("Runner configuration file: NONE");
+    return new Properties();
+  }
+
+  private Properties loadProjectProperties() throws IOException {
+    Properties cliProps = cli.properties();
+    File rootSettingsFile = locatePropertiesFile(cliProps, cliProps.containsKey(PROPERTY_PROJECT_BASEDIR) ? PROPERTY_PROJECT_BASEDIR : PROJECT_HOME,
+      SONAR_PROJECT_PROPERTIES_FILENAME,
+      PROJECT_SETTINGS);
+    if (rootSettingsFile != null && rootSettingsFile.isFile() && rootSettingsFile.exists()) {
+      logger.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;
+    }
+    logger.info("Project configuration file: NONE");
+    return new Properties();
+  }
+
+  private static 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, prefix + module + ".");
+        // and finally add this child properties to global props
+        merge(projectProps, prefix, module, moduleProps);
+      }
+    }
+
+  }
+
+  private static 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);
+      setProjectBaseDir(baseDir, 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(MessageFormat.format("The base directory of the module ''{0}'' does not exist: {1}", moduleId, 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 static File locatePropertiesFile(Properties props, String homeKey, String relativePathFromHome, String settingsKey) {
+    File settingsFile = null;
+    String runnerHome = props.getProperty(homeKey, "");
+    if (!"".equals(runnerHome)) {
+      settingsFile = new File(runnerHome, relativePathFromHome);
+    }
+
+    if (settingsFile == null || !settingsFile.exists()) {
+      String settingsPath = props.getProperty(settingsKey, "");
+      if (!"".equals(settingsPath)) {
+        settingsFile = new File(settingsPath);
+      }
+    }
+    return settingsFile;
+  }
+
+  private static Properties toProperties(File file) {
+    InputStream in = null;
+    try {
+      Properties properties = new Properties();
+      in = new FileInputStream(file);
+      properties.load(in);
+      // Trim properties
+      for (String propKey : properties.stringPropertyNames()) {
+        properties.setProperty(propKey, properties.getProperty(propKey).trim());
+      }
+      return properties;
+
+    } catch (Exception e) {
+      throw new IllegalStateException("Fail to load file: " + file.getAbsolutePath(), e);
+
+    } finally {
+      if (in != null) {
+        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 static void tryToFindAndLoadPropsFile(File baseDir, Properties moduleProps, String moduleId) {
+    File propertyFile = new File(baseDir, SONAR_PROJECT_PROPERTIES_FILENAME);
+    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, "").trim();
+    if (value.isEmpty()) {
+      return new String[0];
+    }
+    String[] values = value.split(",");
+    List<String> trimmedValues = new ArrayList<>();
+    for (int i = 0; i < values.length; i++) {
+      String trimmedValue = values[i].trim();
+      if (!trimmedValue.isEmpty()) {
+        trimmedValues.add(trimmedValue);
+      }
+    }
+    return trimmedValues.toArray(new String[trimmedValues.size()]);
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/Exit.java b/src/main/java/org/sonarsource/scanner/cli/Exit.java
new file mode 100644 (file)
index 0000000..809d863
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+class Exit {
+  static final int SUCCESS = 0;
+  static final int ERROR = 1;
+
+  void exit(int status) {
+    System.exit(status);
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/Logs.java b/src/main/java/org/sonarsource/scanner/cli/Logs.java
new file mode 100644 (file)
index 0000000..ab9b255
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import java.io.PrintStream;
+
+public class Logs {
+  private boolean debugEnabled = false;
+  private boolean displayStackTrace = false;
+  private PrintStream stdOut;
+  private PrintStream stdErr;
+
+  public Logs(PrintStream stdOut, PrintStream stdErr) {
+    this.stdErr = stdErr;
+    this.stdOut = stdOut;
+  }
+
+  public void setDebugEnabled(boolean debugEnabled) {
+    this.debugEnabled = debugEnabled;
+  }
+
+  public void setDisplayStackTrace(boolean displayStackTrace) {
+    this.displayStackTrace = displayStackTrace;
+  }
+
+  public boolean isDebugEnabled() {
+    return debugEnabled;
+  }
+
+  public void debug(String message) {
+    if (isDebugEnabled()) {
+      stdOut.println("DEBUG: " + message);
+    }
+  }
+
+  public void info(String message) {
+    stdOut.println("INFO: " + message);
+  }
+
+  public void warn(String message) {
+    stdOut.println("WARN: " + message);
+  }
+
+  public void error(String message) {
+    stdErr.println("ERROR: " + message);
+  }
+
+  public void error(String message, Throwable t) {
+    stdErr.println("ERROR: " + message);
+    if (t != null && displayStackTrace) {
+      t.printStackTrace(stdErr);
+    }
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/Main.java b/src/main/java/org/sonarsource/scanner/cli/Main.java
new file mode 100644 (file)
index 0000000..06cdc44
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+import org.sonar.runner.api.EmbeddedRunner;
+
+/**
+ * Arguments :
+ * <ul>
+ * <li>runner.home: optional path to runner home (root directory with sub-directories bin, lib and conf)</li>
+ * <li>runner.settings: optional path to runner global settings, usually ${runner.home}/conf/sonar-runner.properties.
+ * This property is used only if ${runner.home} is not defined</li>
+ * <li>project.home: path to project root directory. If not set, then it's supposed to be the directory where the runner is executed</li>
+ * <li>project.settings: optional path to project settings. Default value is ${project.home}/sonar-project.properties.</li>
+ * </ul>
+ *
+ * @since 1.0
+ */
+public class Main {
+
+  private final Shutdown shutdown;
+  private final Cli cli;
+  private final Conf conf;
+  private EmbeddedRunner runner;
+  private BufferedReader inputReader;
+  private RunnerFactory runnerFactory;
+  private Logs logger;
+
+  Main(Shutdown shutdown, Cli cli, Conf conf, RunnerFactory runnerFactory, Logs logger) {
+    this.shutdown = shutdown;
+    this.cli = cli;
+    this.conf = conf;
+    this.runnerFactory = runnerFactory;
+    this.logger = logger;
+  }
+
+  public static void main(String[] args) {
+    Exit exit = new Exit();
+    Logs logs = new Logs(System.out, System.err);
+    Cli cli = new Cli(exit, logs).parse(args);
+    cli.verify();
+    Shutdown shutdown = new Shutdown(exit, cli.isInteractive());
+    Main main = new Main(shutdown, cli, new Conf(cli, logs), new RunnerFactory(logs), logs);
+    main.execute();
+  }
+
+  void execute() {
+    Stats stats = new Stats(logger).start();
+
+    try {
+      Properties p = conf.properties();
+      init(p);
+      runner.start();
+
+      if (cli.isInteractive()) {
+        interactiveLoop(p);
+      } else {
+        runAnalysis(stats, p);
+      }
+    } catch (Exception e) {
+      displayExecutionResult(stats, "FAILURE");
+      showError("Error during Sonar runner execution", e, cli.isDisplayStackTrace());
+      shutdown.exit(Exit.ERROR);
+    }
+
+    runner.stop();
+    shutdown.exit(Exit.SUCCESS);
+  }
+
+  private void interactiveLoop(Properties p) throws IOException {
+    do {
+      Stats stats = new Stats(logger).start();
+      try {
+        runAnalysis(stats, p);
+      } catch (Exception e) {
+        displayExecutionResult(stats, "FAILURE");
+        showError("Error during Sonar runner execution", e, cli.isDisplayStackTrace());
+      }
+    } while (waitForUser());
+  }
+
+  private void init(Properties p) throws IOException {
+    SystemInfo.print(logger);
+    if (cli.isDisplayVersionOnly()) {
+      shutdown.exit(Exit.SUCCESS);
+    }
+
+    if (cli.isDisplayStackTrace()) {
+      logger.info("Error stacktraces are turned on.");
+    }
+
+    runner = runnerFactory.create(p);
+  }
+
+  private void runAnalysis(Stats stats, Properties p) {
+    runner.runAnalysis(p);
+    displayExecutionResult(stats, "SUCCESS");
+  }
+
+  private boolean waitForUser() throws IOException {
+    if (inputReader == null) {
+      inputReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
+    }
+
+    shutdown.signalReady(true);
+    if (shutdown.shouldExit()) {
+      // exit before displaying message
+      return false;
+    }
+
+    System.out.println("");
+    System.out.println("<Press enter to restart analysis or Ctrl+C to exit the interactive mode>");
+    String line = inputReader.readLine();
+    shutdown.signalReady(false);
+
+    return line != null;
+  }
+
+  // Visible for testing
+  void setInputReader(BufferedReader inputReader) {
+    this.inputReader = inputReader;
+  }
+
+  private void displayExecutionResult(Stats stats, String resultMsg) {
+    logger.info("------------------------------------------------------------------------");
+    logger.info("EXECUTION " + resultMsg);
+    logger.info("------------------------------------------------------------------------");
+    stats.stop();
+    logger.info("------------------------------------------------------------------------");
+  }
+
+  private void showError(String message, Throwable e, boolean showStackTrace) {
+    if (showStackTrace) {
+      logger.error(message, e);
+      if (!cli.isDebugMode()) {
+        logger.error("");
+        suggestDebugMode();
+      }
+    } else {
+      logger.error(message);
+      if (e != null) {
+        logger.error(e.getMessage());
+        String previousMsg = "";
+        for (Throwable cause = e.getCause(); cause != null
+          && cause.getMessage() != null
+          && !cause.getMessage().equals(previousMsg); cause = cause.getCause()) {
+          logger.error("Caused by: " + cause.getMessage());
+          previousMsg = cause.getMessage();
+        }
+      }
+      logger.error("");
+      logger.error("To see the full stack trace of the errors, re-run SonarQube Runner with the -e switch.");
+      if (!cli.isDebugMode()) {
+        suggestDebugMode();
+      }
+    }
+  }
+
+  private void suggestDebugMode() {
+    logger.error("Re-run SonarQube Runner using the -X switch to enable full debug logging.");
+  }
+
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/RunnerFactory.java b/src/main/java/org/sonarsource/scanner/cli/RunnerFactory.java
new file mode 100644 (file)
index 0000000..fbfa831
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import java.util.Properties;
+import org.sonar.runner.api.EmbeddedRunner;
+import org.sonar.runner.api.LogOutput;
+
+class RunnerFactory {
+
+  private final Logs logger;
+
+  public RunnerFactory(Logs logger) {
+    this.logger = logger;
+  }
+
+  EmbeddedRunner create(Properties props) {
+    return EmbeddedRunner.create(new DefaultLogOutput()).addGlobalProperties(props);
+  }
+
+  class DefaultLogOutput implements LogOutput {
+    @Override
+    public void log(String formattedMessage, Level level) {
+      switch (level) {
+        case TRACE:
+        case DEBUG:
+          logger.debug(formattedMessage);
+          break;
+        case ERROR:
+          logger.error(formattedMessage);
+          break;
+        case INFO:
+        case WARN:
+        default:
+          logger.info(formattedMessage);
+      }
+    }
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/Shutdown.java b/src/main/java/org/sonarsource/scanner/cli/Shutdown.java
new file mode 100644 (file)
index 0000000..ed81ae1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+class Shutdown {
+  static final int SUCCESS = 0;
+  static final int ERROR = 1;
+  private static final long DEFAULT_MAX_WAIT = 10_000;
+
+  private long maxWait;
+  ShutdownHook hook = new ShutdownHook();
+  private boolean isReady = false;
+  private boolean exiting = false;
+  private Object lock = new Object();
+  private Exit exit;
+
+  Shutdown(Exit exit, boolean isInteractive) {
+    this(exit, isInteractive, DEFAULT_MAX_WAIT);
+  }
+
+  Shutdown(Exit exit, boolean isInteractive, long maxWait) {
+    this.maxWait = maxWait;
+    this.exit = exit;
+    if (isInteractive) {
+      Runtime.getRuntime().addShutdownHook(hook);
+    }
+  }
+
+  void exit(int status) {
+    synchronized (lock) {
+      signalReady(true);
+    }
+    exit.exit(status);
+  }
+
+  void signalReady(boolean ready) {
+    synchronized (lock) {
+      this.isReady = ready;
+      lock.notifyAll();
+    }
+  }
+
+  boolean shouldExit() {
+    synchronized (lock) {
+      return exiting;
+    }
+  }
+
+  class ShutdownHook extends Thread {
+    private ShutdownHook() {
+      this.setName("shutdown-hook");
+    }
+
+    @Override
+    public void run() {
+      long startTime = System.currentTimeMillis();
+      synchronized (lock) {
+        exiting = true;
+
+        while (!isReady) {
+          long waitTime = startTime + maxWait - System.currentTimeMillis();
+          if (waitTime <= 0) {
+            break;
+          }
+
+          try {
+            lock.wait(waitTime);
+          } catch (InterruptedException e) {
+            // continue
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/Stats.java b/src/main/java/org/sonarsource/scanner/cli/Stats.java
new file mode 100644 (file)
index 0000000..0cfb333
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+class Stats {
+  private final Logs logger;
+  private long startTime;
+
+  Stats(Logs logger) {
+    this.logger = logger;
+  }
+
+  Stats start() {
+    startTime = System.currentTimeMillis();
+    return this;
+  }
+
+  Stats stop() {
+    long stopTime = System.currentTimeMillis() - startTime;
+    logger.info("Total time: " + formatTime(stopTime));
+
+    System.gc();
+    Runtime r = Runtime.getRuntime();
+    long mb = 1024L * 1024;
+    logger.info("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M");
+
+    return this;
+  }
+
+  static String formatTime(long time) {
+    long h = time / (60 * 60 * 1000);
+    long m = (time - h * 60 * 60 * 1000) / (60 * 1000);
+    long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000;
+    long ms = time % 1000;
+    final String format;
+    if (h > 0) {
+      format = "%1$d:%2$02d:%3$02d.%4$03ds";
+    } else if (m > 0) {
+      format = "%2$d:%3$02d.%4$03ds";
+    } else {
+      format = "%3$d.%4$03ds";
+    }
+    return String.format(format, h, m, s, ms);
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/SystemInfo.java b/src/main/java/org/sonarsource/scanner/cli/SystemInfo.java
new file mode 100644 (file)
index 0000000..35075e0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import org.sonar.runner.api.RunnerVersion;
+
+class SystemInfo {
+  private static System2 system = new System2();
+
+  private SystemInfo() {
+  }
+
+  static void setSystem(System2 system) {
+    SystemInfo.system = system;
+  }
+
+  static void print(Logs logger) {
+    logger.info("SonarQube Runner " + RunnerVersion.version());
+    logger.info(java());
+    logger.info(os());
+    String runnerOpts = system.getenv("SONAR_RUNNER_OPTS");
+    if (runnerOpts != null) {
+      logger.info("SONAR_RUNNER_OPTS=" + runnerOpts);
+    }
+  }
+
+  static String java() {
+    StringBuilder sb = new StringBuilder();
+    sb
+      .append("Java ")
+      .append(system.getProperty("java.version"))
+      .append(" ")
+      .append(system.getProperty("java.vendor"));
+    String bits = system.getProperty("sun.arch.data.model");
+    if ("32".equals(bits) || "64".equals(bits)) {
+      sb.append(" (").append(bits).append("-bit)");
+    }
+    return sb.toString();
+  }
+
+  static String os() {
+    StringBuilder sb = new StringBuilder();
+    sb
+      .append(system.getProperty("os.name"))
+      .append(" ")
+      .append(system.getProperty("os.version"))
+      .append(" ")
+      .append(system.getProperty("os.arch"));
+    return sb.toString();
+  }
+
+  static class System2 {
+    String getProperty(String key) {
+      return System.getProperty(key);
+    }
+
+    String getenv(String key) {
+      return System.getenv(key);
+    }
+  }
+}
diff --git a/src/main/java/org/sonarsource/scanner/cli/package-info.java b/src/main/java/org/sonarsource/scanner/cli/package-info.java
new file mode 100644 (file)
index 0000000..09df639
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+@ParametersAreNonnullByDefault
+package org.sonarsource.scanner.cli;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/src/test/java/org/sonar/runner/cli/CliTest.java b/src/test/java/org/sonar/runner/cli/CliTest.java
deleted file mode 100644 (file)
index 4afd99d..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class CliTest {
-  Exit exit = mock(Exit.class);
-  Logs logs = new Logs(System.out, System.err);
-  Cli cli = new Cli(exit, logs);
-
-  @Test
-  public void should_parse_empty_arguments() {
-    cli.parse(new String[0]);
-    assertThat(cli.properties()).isNotEmpty();
-    assertThat(cli.isDebugMode()).isFalse();
-    assertThat(cli.isDisplayStackTrace()).isFalse();
-    assertThat(cli.isDisplayVersionOnly()).isFalse();
-  }
-
-  @Test
-  public void should_extract_properties() {
-    cli.parse(new String[] {"-D", "foo=bar", "--define", "hello=world", "-Dboolean"});
-    assertThat(cli.properties().get("foo")).isEqualTo("bar");
-    assertThat(cli.properties().get("hello")).isEqualTo("world");
-    assertThat(cli.properties().get("boolean")).isEqualTo("true");
-  }
-
-  @Test
-  public void dont_allow_interactive_fork() {
-    cli.parse(new String[] {"-i", "-DsonarRunner.mode=fork"});
-    cli.verify();
-    verify(exit).exit(Exit.SUCCESS);
-  }
-
-  @Test
-  public void should_parse_optional_task() {
-    cli.parse(new String[] {"-D", "foo=bar"});
-    assertThat(cli.properties().get("sonar.task")).isNull();
-
-    cli.parse(new String[] {"views", "-D", "foo=bar"});
-    assertThat(cli.properties().get("sonar.task")).isEqualTo("views");
-  }
-
-  @Test
-  public void should_enable_debug_mode() {
-    cli.parse(new String[] {"-X"});
-    assertThat(cli.isDebugMode()).isTrue();
-    assertThat(cli.isDisplayStackTrace()).isTrue();
-    assertThat(cli.properties().get("sonar.verbose")).isEqualTo("true");
-  }
-
-  @Test
-  public void should_enable_stacktrace_log() {
-    cli.parse(new String[] {"-e"});
-    assertThat(cli.isDebugMode()).isFalse();
-    assertThat(cli.isDisplayStackTrace()).isTrue();
-    assertThat(cli.properties().get("sonar.verbose")).isNull();
-  }
-
-  @Test
-  public void should_disable_debug_mode_and_stacktrace_log_by_default() {
-    cli.parse(new String[0]);
-    assertThat(cli.isDebugMode()).isFalse();
-    assertThat(cli.isDisplayStackTrace()).isFalse();
-    assertThat(cli.properties().get("sonar.verbose")).isNull();
-  }
-}
diff --git a/src/test/java/org/sonar/runner/cli/ConfTest.java b/src/test/java/org/sonar/runner/cli/ConfTest.java
deleted file mode 100644 (file)
index 0bce176..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import java.io.File;
-import java.util.Properties;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ConfTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  Properties args = new Properties();
-  Logs logs = new Logs(System.out, System.err);
-  Cli cli = mock(Cli.class);
-  Conf conf = new Conf(cli, logs);
-
-  @Before
-  public void initConf() {
-    when(cli.properties()).thenReturn(args);
-  }
-
-  @Test
-  public void should_load_global_settings_by_home() throws Exception {
-    File home = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByHome/").toURI());
-    args.setProperty("runner.home", home.getCanonicalPath());
-
-    assertThat(conf.properties().get("sonar.prop")).isEqualTo("value");
-  }
-
-  @Test
-  public void should_not_fail_if_no_home() throws Exception {
-    assertThat(conf.properties()).isNotEmpty();
-  }
-
-  @Test
-  public void should_load_conf_by_direct_path() throws Exception {
-    File settings = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties").toURI());
-    args.setProperty("runner.settings", settings.getCanonicalPath());
-
-    assertThat(conf.properties().get("sonar.prop")).isEqualTo("otherValue");
-  }
-
-  @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 shouldSupportDeepModuleConfigurationInRoot() throws Exception {
-    File projectHome = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project").toURI());
-    args.setProperty("project.home", projectHome.getCanonicalPath());
-
-    Properties properties = conf.properties();
-
-    assertThat(properties.getProperty("1.sonar.projectName")).isEqualTo("Module 1");
-    assertThat(properties.getProperty("1.11.sonar.projectName")).isEqualTo("Module 11");
-    assertThat(properties.getProperty("1.11.111.sonar.projectName")).isEqualTo("Module 111");
-    assertThat(properties.getProperty("1.12.sonar.projectName")).isEqualTo("Module 12");
-    assertThat(properties.getProperty("2.sonar.projectName")).isEqualTo("Module 2");
-
-    // SONARUNNER-125
-    assertThat(properties.getProperty("11.111.sonar.projectName")).isNull();
-  }
-
-  @Test
-  public void shouldLoadModuleConfigurationOverrideBasedir() throws Exception {
-    File projectHome = new File(getClass().getResource("/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/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");
-    assertThat(properties.getProperty("module3.sonar.projectName")).isEqualTo("Module 3");
-  }
-
-  @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");
-  }
-
-  @Test
-  public void ignoreEmptyModule() throws Exception {
-    File projectHome = new File(getClass().getResource("/org/sonar/runner/ConfTest/emptyModules/project").toURI());
-    args.setProperty("project.home", temp.newFolder().getCanonicalPath());
-    args.setProperty("sonar.projectBaseDir", projectHome.getCanonicalPath());
-
-    conf.properties();
-  }
-
-  @Test
-  public void shouldGetList() {
-    Properties props = new Properties();
-
-    props.put("prop", "  foo  ,,  bar  , \n\ntoto,tutu");
-    assertThat(Conf.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu");
-  }
-
-}
diff --git a/src/test/java/org/sonar/runner/cli/LogsTest.java b/src/test/java/org/sonar/runner/cli/LogsTest.java
deleted file mode 100644 (file)
index 02a49b4..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.PrintStream;
-
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verify;
-
-public class LogsTest {
-  @Mock
-  private PrintStream stdOut;
-
-  @Mock
-  private PrintStream stdErr;
-
-  private Logs logs;
-
-  @Before
-  public void setUp() {
-    MockitoAnnotations.initMocks(this);
-    logs = new Logs(stdOut, stdErr);
-  }
-
-  @Test
-  public void testInfo() {
-    logs.info("info");
-    verify(stdOut).println("INFO: info");
-    verifyNoMoreInteractions(stdOut, stdErr);
-  }
-  
-  @Test
-  public void testError() {
-    Exception e = new NullPointerException("exception");
-    logs.setDisplayStackTrace(false);
-    logs.error("error1");
-    verify(stdErr).println("ERROR: error1");
-    
-    logs.error("error2", e);
-    verify(stdErr).println("ERROR: error2");
-    
-    verifyNoMoreInteractions(stdOut, stdErr);
-    
-    logs.setDisplayStackTrace(true);
-    logs.error("error3", e);
-    verify(stdErr).println("ERROR: error3");
-    // other interactions to print the exception..
-  }
-
-  @Test
-  public void testDebug() {
-    logs.setDebugEnabled(true);
-
-    logs.debug("debug");
-    verify(stdOut).println("DEBUG: debug");
-
-    logs.setDebugEnabled(false);
-    logs.debug("debug");
-    verifyNoMoreInteractions(stdOut, stdErr);
-  }
-}
diff --git a/src/test/java/org/sonar/runner/cli/MainTest.java b/src/test/java/org/sonar/runner/cli/MainTest.java
deleted file mode 100644 (file)
index 45f85a8..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Properties;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.sonar.runner.api.EmbeddedRunner;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class MainTest {
-
-  @Mock
-  private Shutdown shutdown;
-  @Mock
-  private Cli cli;
-  @Mock
-  private Conf conf;
-  @Mock
-  private Properties properties;
-  @Mock
-  private RunnerFactory runnerFactory;
-  @Mock
-  private EmbeddedRunner runner;
-  @Mock
-  private Logs logs;
-
-  @Before
-  public void setUp() throws IOException {
-    MockitoAnnotations.initMocks(this);
-    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
-    when(conf.properties()).thenReturn(properties);
-
-  }
-
-  @Test
-  public void should_execute_runner() {
-    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
-    main.execute();
-
-    verify(shutdown).exit(Exit.SUCCESS);
-    verify(runnerFactory).create(properties);
-
-    verify(runner, times(1)).start();
-    verify(runner, times(1)).runAnalysis(properties);
-    verify(runner, times(1)).stop();
-  }
-
-  @Test
-  public void should_stop_on_error() {
-    EmbeddedRunner runner = mock(EmbeddedRunner.class);
-    Exception e = new NullPointerException("NPE");
-    e = new IllegalStateException("Error", e);
-    doThrow(e).when(runner).runAnalysis(any(Properties.class));
-    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
-
-    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
-    main.execute();
-
-    verify(runner).stop();
-    verify(shutdown).exit(Exit.ERROR);
-    verify(logs).error("Caused by: NPE");
-
-  }
-
-  @Test
-  public void show_error_stacktrace() {
-    Exception e = new NullPointerException("NPE");
-    e = new IllegalStateException("Error", e);
-    when(cli.isDisplayStackTrace()).thenReturn(true);
-
-    EmbeddedRunner runner = mock(EmbeddedRunner.class);
-    doThrow(e).when(runner).runAnalysis(any(Properties.class));
-    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
-
-    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
-    main.execute();
-
-    verify(runner).stop();
-    verify(shutdown).exit(Exit.ERROR);
-    verify(logs).error("Error during Sonar runner execution", e);
-  }
-
-  @Test
-  public void should_not_stop_on_error_in_interactive_mode() throws Exception {
-    EmbeddedRunner runner = mock(EmbeddedRunner.class);
-    doThrow(new IllegalStateException("Error")).when(runner).runAnalysis(any(Properties.class));
-    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
-    when(cli.isInteractive()).thenReturn(true);
-
-    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
-    BufferedReader inputReader = mock(BufferedReader.class);
-    when(inputReader.readLine()).thenReturn("");
-    when(shutdown.shouldExit()).thenReturn(false).thenReturn(true);
-    main.setInputReader(inputReader);
-    main.execute();
-
-    verify(runner, times(2)).runAnalysis(any(Properties.class));
-    verify(runner).stop();
-    verify(shutdown).exit(Exit.SUCCESS);
-  }
-
-  @Test
-  public void should_only_display_version() throws IOException {
-
-    Properties p = new Properties();
-    when(cli.isDisplayVersionOnly()).thenReturn(true);
-    when(conf.properties()).thenReturn(p);
-
-    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
-    main.execute();
-
-    InOrder inOrder = Mockito.inOrder(shutdown, runnerFactory);
-
-    inOrder.verify(shutdown, times(1)).exit(Exit.SUCCESS);
-    inOrder.verify(runnerFactory, times(1)).create(p);
-    inOrder.verify(shutdown, times(1)).exit(Exit.SUCCESS);
-  }
-
-  @Test(timeout = 30000)
-  public void test_interactive_mode() throws IOException {
-    String inputStr = "qwe" + System.lineSeparator() + "qwe" + System.lineSeparator();
-    InputStream input = new ByteArrayInputStream(inputStr.getBytes(StandardCharsets.UTF_8));
-    System.setIn(input);
-    input.close();
-
-    when(cli.isInteractive()).thenReturn(true);
-    when(cli.isDebugMode()).thenReturn(true);
-    when(cli.isDisplayStackTrace()).thenReturn(true);
-
-    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
-    main.execute();
-
-    verify(runner, times(1)).start();
-    verify(runner, times(3)).runAnalysis(any(Properties.class));
-    verify(runner, times(1)).stop();
-  }
-}
diff --git a/src/test/java/org/sonar/runner/cli/RunnerFactoryTest.java b/src/test/java/org/sonar/runner/cli/RunnerFactoryTest.java
deleted file mode 100644 (file)
index 9ae2bfb..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import org.sonar.runner.api.LogOutput.Level;
-import org.sonar.runner.api.LogOutput;
-import org.junit.Before;
-
-import java.util.Properties;
-
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.mock;
-import org.junit.Test;
-import org.sonar.runner.api.EmbeddedRunner;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RunnerFactoryTest {
-
-  Properties props = new Properties();
-  Logs logs;
-
-  @Before
-  public void setUp() {
-    logs = mock(Logs.class);
-  }
-
-  @Test
-  public void should_create_embedded_runner() {
-    props.setProperty("foo", "bar");
-    EmbeddedRunner runner = new RunnerFactory(logs).create(props);
-
-    assertThat(runner).isInstanceOf(EmbeddedRunner.class);
-    assertThat(runner.globalProperties().get("foo")).isEqualTo("bar");
-  }
-
-  @Test
-  public void should_fwd_logs() {
-    LogOutput logOutput = new RunnerFactory(logs).new DefaultLogOutput();
-
-    String msg = "test";
-
-    logOutput.log(msg, Level.DEBUG);
-    verify(logs).debug(msg);
-    verifyNoMoreInteractions(logs);
-    reset(logs);
-
-    logOutput.log(msg, Level.INFO);
-    verify(logs).info(msg);
-    verifyNoMoreInteractions(logs);
-    reset(logs);
-
-    logOutput.log(msg, Level.ERROR);
-    verify(logs).error(msg);
-    verifyNoMoreInteractions(logs);
-    reset(logs);
-
-    logOutput.log(msg, Level.WARN);
-    verify(logs).info(msg);
-    verifyNoMoreInteractions(logs);
-    reset(logs);
-
-    logOutput.log(msg, Level.TRACE);
-    verify(logs).debug(msg);
-    verifyNoMoreInteractions(logs);
-    reset(logs);
-  }
-
-}
diff --git a/src/test/java/org/sonar/runner/cli/ShutdownTest.java b/src/test/java/org/sonar/runner/cli/ShutdownTest.java
deleted file mode 100644 (file)
index d41cf4e..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import com.jayway.awaitility.Duration;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static com.jayway.awaitility.Awaitility.await;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.verify;
-
-public class ShutdownTest {
-  @Mock
-  private Exit exit;
-  private Shutdown shutdown;
-
-  @Before
-  public void setUp() {
-    MockitoAnnotations.initMocks(this);
-    shutdown = new Shutdown(exit, true);
-  }
-
-  @Test
-  public void testShutdown() {
-    shutdown.exit(3);
-    verify(exit).exit(3);
-  }
-
-  @Test(timeout = 60_000)
-  public void testWaitReady() throws InterruptedException {
-    shutdown = new Shutdown(exit, true, 100_000);
-    shutdown.signalReady(false);
-    assertThat(shutdown.shouldExit()).isFalse();
-
-    final Thread t = new HookCaller();
-    t.start();
-
-    await().atMost(Duration.TWO_SECONDS).pollDelay(50, TimeUnit.MILLISECONDS).until(new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return t.isAlive();
-      }
-    });
-
-    assertThat(shutdown.shouldExit()).isTrue();
-
-    shutdown.signalReady(true);
-    t.join();
-  }
-
-  @Test(timeout = 60_000)
-  public void testTimeout() throws InterruptedException {
-    shutdown = new Shutdown(exit, true, 0);
-
-    Thread t = new HookCaller();
-    t.start();
-    t.join();
-  }
-
-  private class HookCaller extends Thread {
-    @Override
-    public void run() {
-      shutdown.hook.run();
-    }
-  }
-}
diff --git a/src/test/java/org/sonar/runner/cli/StatsTest.java b/src/test/java/org/sonar/runner/cli/StatsTest.java
deleted file mode 100644 (file)
index 8523a1c..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import org.mockito.Mockito;
-
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.mock;
-import org.junit.Test;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class StatsTest {
-  private PrintStream stdOut = mock(PrintStream.class);
-  private PrintStream stdErr;
-  private Logs logs = new Logs(stdOut, stdErr);
-
-  @Test
-  public void shouldPrintStats() throws UnsupportedEncodingException {
-    new Stats(logs).start().stop();
-
-    verify(stdOut).println(Mockito.contains("Total time: "));
-    verify(stdOut).println(Mockito.contains("Final Memory: "));
-  }
-
-  @Test
-  public void shouldFormatTime() {
-    assertThat(Stats.formatTime(1 * 60 * 60 * 1000 + 2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("1:02:03.400s");
-    assertThat(Stats.formatTime(2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("2:03.400s");
-    assertThat(Stats.formatTime(3 * 1000 + 400)).isEqualTo("3.400s");
-    assertThat(Stats.formatTime(400)).isEqualTo("0.400s");
-  }
-}
diff --git a/src/test/java/org/sonar/runner/cli/SystemInfoTest.java b/src/test/java/org/sonar/runner/cli/SystemInfoTest.java
deleted file mode 100644 (file)
index ea5ba37..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube Scanner
- * Copyright (C) 2011 SonarSource
- * sonarqube@googlegroups.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  02
- */
-package org.sonar.runner.cli;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import org.sonar.runner.api.RunnerVersion;
-import org.junit.Before;
-import org.sonar.runner.cli.SystemInfo.System2;
-import org.junit.Test;
-import org.sonar.runner.cli.SystemInfo;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class SystemInfoTest {
-  System2 mockSystem;
-  Logs logs;
-
-  @Before
-  public void setUp() {
-    mockSystem = mock(System2.class);
-    logs = mock(Logs.class);
-    SystemInfo.setSystem(mockSystem);
-  }
-
-  @Test
-  public void test_java() {
-    mockJava();
-    assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle (64-bit)");
-
-    when(mockSystem.getProperty("sun.arch.data.model")).thenReturn("32");
-    assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle (32-bit)");
-
-    when(mockSystem.getProperty("sun.arch.data.model")).thenReturn(null);
-    assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle");
-  }
-
-  @Test
-  public void test_os() {
-    mockOs();
-
-    assertThat(SystemInfo.os()).isEqualTo("linux 2.5 x64");
-  }
-
-  private void mockJava() {
-    when(mockSystem.getProperty("java.version")).thenReturn("1.9");
-    when(mockSystem.getProperty("java.vendor")).thenReturn("oracle");
-    when(mockSystem.getProperty("sun.arch.data.model")).thenReturn("64");
-  }
-
-  private void mockOs() {
-    when(mockSystem.getProperty("os.version")).thenReturn("2.5");
-    when(mockSystem.getProperty("os.arch")).thenReturn("x64");
-    when(mockSystem.getProperty("os.name")).thenReturn("linux");
-  }
-
-  @Test
-  public void should_print() {
-    mockOs();
-    mockJava();
-    when(mockSystem.getenv("SONAR_RUNNER_OPTS")).thenReturn("arg");
-
-    SystemInfo.print(logs);
-
-    verify(mockSystem).getProperty("java.version");
-    verify(mockSystem).getProperty("os.version");
-    verify(mockSystem).getenv("SONAR_RUNNER_OPTS");
-
-    verify(logs).info("SonarQube Runner " + RunnerVersion.version());
-    verify(logs).info("Java 1.9 oracle (64-bit)");
-    verify(logs).info("linux 2.5 x64");
-    verify(logs).info("SONAR_RUNNER_OPTS=arg");
-    verifyNoMoreInteractions(logs);
-  }
-}
diff --git a/src/test/java/org/sonarsource/scanner/cli/CliTest.java b/src/test/java/org/sonarsource/scanner/cli/CliTest.java
new file mode 100644 (file)
index 0000000..564146c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import org.junit.Test;
+import org.sonarsource.scanner.cli.Cli;
+import org.sonarsource.scanner.cli.Exit;
+import org.sonarsource.scanner.cli.Logs;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class CliTest {
+  Exit exit = mock(Exit.class);
+  Logs logs = new Logs(System.out, System.err);
+  Cli cli = new Cli(exit, logs);
+
+  @Test
+  public void should_parse_empty_arguments() {
+    cli.parse(new String[0]);
+    assertThat(cli.properties()).isNotEmpty();
+    assertThat(cli.isDebugMode()).isFalse();
+    assertThat(cli.isDisplayStackTrace()).isFalse();
+    assertThat(cli.isDisplayVersionOnly()).isFalse();
+  }
+
+  @Test
+  public void should_extract_properties() {
+    cli.parse(new String[] {"-D", "foo=bar", "--define", "hello=world", "-Dboolean"});
+    assertThat(cli.properties().get("foo")).isEqualTo("bar");
+    assertThat(cli.properties().get("hello")).isEqualTo("world");
+    assertThat(cli.properties().get("boolean")).isEqualTo("true");
+  }
+
+  @Test
+  public void dont_allow_interactive_fork() {
+    cli.parse(new String[] {"-i", "-DsonarRunner.mode=fork"});
+    cli.verify();
+    verify(exit).exit(Exit.SUCCESS);
+  }
+
+  @Test
+  public void should_parse_optional_task() {
+    cli.parse(new String[] {"-D", "foo=bar"});
+    assertThat(cli.properties().get("sonar.task")).isNull();
+
+    cli.parse(new String[] {"views", "-D", "foo=bar"});
+    assertThat(cli.properties().get("sonar.task")).isEqualTo("views");
+  }
+
+  @Test
+  public void should_enable_debug_mode() {
+    cli.parse(new String[] {"-X"});
+    assertThat(cli.isDebugMode()).isTrue();
+    assertThat(cli.isDisplayStackTrace()).isTrue();
+    assertThat(cli.properties().get("sonar.verbose")).isEqualTo("true");
+  }
+
+  @Test
+  public void should_enable_stacktrace_log() {
+    cli.parse(new String[] {"-e"});
+    assertThat(cli.isDebugMode()).isFalse();
+    assertThat(cli.isDisplayStackTrace()).isTrue();
+    assertThat(cli.properties().get("sonar.verbose")).isNull();
+  }
+
+  @Test
+  public void should_disable_debug_mode_and_stacktrace_log_by_default() {
+    cli.parse(new String[0]);
+    assertThat(cli.isDebugMode()).isFalse();
+    assertThat(cli.isDisplayStackTrace()).isFalse();
+    assertThat(cli.properties().get("sonar.verbose")).isNull();
+  }
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/ConfTest.java b/src/test/java/org/sonarsource/scanner/cli/ConfTest.java
new file mode 100644 (file)
index 0000000..a6d8149
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import java.io.File;
+import java.util.Properties;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ConfTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  Properties args = new Properties();
+  Logs logs = new Logs(System.out, System.err);
+  Cli cli = mock(Cli.class);
+  Conf conf = new Conf(cli, logs);
+
+  @Before
+  public void initConf() {
+    when(cli.properties()).thenReturn(args);
+  }
+
+  @Test
+  public void should_load_global_settings_by_home() throws Exception {
+    File home = new File(getClass().getResource("ConfTest/shouldLoadRunnerSettingsByHome/").toURI());
+    args.setProperty("runner.home", home.getCanonicalPath());
+
+    assertThat(conf.properties().get("sonar.prop")).isEqualTo("value");
+  }
+
+  @Test
+  public void should_not_fail_if_no_home() throws Exception {
+    assertThat(conf.properties()).isNotEmpty();
+  }
+
+  @Test
+  public void should_load_conf_by_direct_path() throws Exception {
+    File settings = new File(getClass().getResource("ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties").toURI());
+    args.setProperty("runner.settings", settings.getCanonicalPath());
+
+    assertThat(conf.properties().get("sonar.prop")).isEqualTo("otherValue");
+  }
+
+  @Test
+  public void shouldLoadCompleteConfiguration() throws Exception {
+    File runnerHome = new File(getClass().getResource("ConfTest/shouldLoadCompleteConfiguration/runner").toURI());
+    File projectHome = new File(getClass().getResource("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("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 shouldSupportDeepModuleConfigurationInRoot() throws Exception {
+    File projectHome = new File(getClass().getResource("ConfTest/shouldSupportDeepModuleConfigurationInRoot/project").toURI());
+    args.setProperty("project.home", projectHome.getCanonicalPath());
+
+    Properties properties = conf.properties();
+
+    assertThat(properties.getProperty("1.sonar.projectName")).isEqualTo("Module 1");
+    assertThat(properties.getProperty("1.11.sonar.projectName")).isEqualTo("Module 11");
+    assertThat(properties.getProperty("1.11.111.sonar.projectName")).isEqualTo("Module 111");
+    assertThat(properties.getProperty("1.12.sonar.projectName")).isEqualTo("Module 12");
+    assertThat(properties.getProperty("2.sonar.projectName")).isEqualTo("Module 2");
+
+    // SONARUNNER-125
+    assertThat(properties.getProperty("11.111.sonar.projectName")).isNull();
+  }
+
+  @Test
+  public void shouldLoadModuleConfigurationOverrideBasedir() throws Exception {
+    File projectHome = new File(getClass().getResource("ConfTest/shouldLoadModuleConfigurationOverrideBasedir/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");
+    assertThat(properties.getProperty("module3.sonar.projectName")).isEqualTo("Module 3");
+  }
+
+  @Test
+  public void shouldSupportSettingBaseDirFromCli() throws Exception {
+    File projectHome = new File(getClass().getResource("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");
+  }
+
+  @Test
+  public void ignoreEmptyModule() throws Exception {
+    File projectHome = new File(getClass().getResource("ConfTest/emptyModules/project").toURI());
+    args.setProperty("project.home", temp.newFolder().getCanonicalPath());
+    args.setProperty("sonar.projectBaseDir", projectHome.getCanonicalPath());
+
+    conf.properties();
+  }
+
+  @Test
+  public void shouldGetList() {
+    Properties props = new Properties();
+
+    props.put("prop", "  foo  ,,  bar  , \n\ntoto,tutu");
+    assertThat(Conf.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu");
+  }
+
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/LogsTest.java b/src/test/java/org/sonarsource/scanner/cli/LogsTest.java
new file mode 100644 (file)
index 0000000..39bedff
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.sonarsource.scanner.cli.Logs;
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verify;
+
+public class LogsTest {
+  @Mock
+  private PrintStream stdOut;
+
+  @Mock
+  private PrintStream stdErr;
+
+  private Logs logs;
+
+  @Before
+  public void setUp() {
+    MockitoAnnotations.initMocks(this);
+    logs = new Logs(stdOut, stdErr);
+  }
+
+  @Test
+  public void testInfo() {
+    logs.info("info");
+    verify(stdOut).println("INFO: info");
+    verifyNoMoreInteractions(stdOut, stdErr);
+  }
+  
+  @Test
+  public void testError() {
+    Exception e = new NullPointerException("exception");
+    logs.setDisplayStackTrace(false);
+    logs.error("error1");
+    verify(stdErr).println("ERROR: error1");
+    
+    logs.error("error2", e);
+    verify(stdErr).println("ERROR: error2");
+    
+    verifyNoMoreInteractions(stdOut, stdErr);
+    
+    logs.setDisplayStackTrace(true);
+    logs.error("error3", e);
+    verify(stdErr).println("ERROR: error3");
+    // other interactions to print the exception..
+  }
+
+  @Test
+  public void testDebug() {
+    logs.setDebugEnabled(true);
+
+    logs.debug("debug");
+    verify(stdOut).println("DEBUG: debug");
+
+    logs.setDebugEnabled(false);
+    logs.debug("debug");
+    verifyNoMoreInteractions(stdOut, stdErr);
+  }
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/MainTest.java b/src/test/java/org/sonarsource/scanner/cli/MainTest.java
new file mode 100644 (file)
index 0000000..6875d1e
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.sonar.runner.api.EmbeddedRunner;
+import org.sonarsource.scanner.cli.Cli;
+import org.sonarsource.scanner.cli.Conf;
+import org.sonarsource.scanner.cli.Exit;
+import org.sonarsource.scanner.cli.Logs;
+import org.sonarsource.scanner.cli.Main;
+import org.sonarsource.scanner.cli.RunnerFactory;
+import org.sonarsource.scanner.cli.Shutdown;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MainTest {
+
+  @Mock
+  private Shutdown shutdown;
+  @Mock
+  private Cli cli;
+  @Mock
+  private Conf conf;
+  @Mock
+  private Properties properties;
+  @Mock
+  private RunnerFactory runnerFactory;
+  @Mock
+  private EmbeddedRunner runner;
+  @Mock
+  private Logs logs;
+
+  @Before
+  public void setUp() throws IOException {
+    MockitoAnnotations.initMocks(this);
+    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
+    when(conf.properties()).thenReturn(properties);
+
+  }
+
+  @Test
+  public void should_execute_runner() {
+    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
+    main.execute();
+
+    verify(shutdown).exit(Exit.SUCCESS);
+    verify(runnerFactory).create(properties);
+
+    verify(runner, times(1)).start();
+    verify(runner, times(1)).runAnalysis(properties);
+    verify(runner, times(1)).stop();
+  }
+
+  @Test
+  public void should_stop_on_error() {
+    EmbeddedRunner runner = mock(EmbeddedRunner.class);
+    Exception e = new NullPointerException("NPE");
+    e = new IllegalStateException("Error", e);
+    doThrow(e).when(runner).runAnalysis(any(Properties.class));
+    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
+
+    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
+    main.execute();
+
+    verify(runner).stop();
+    verify(shutdown).exit(Exit.ERROR);
+    verify(logs).error("Caused by: NPE");
+
+  }
+
+  @Test
+  public void show_error_stacktrace() {
+    Exception e = new NullPointerException("NPE");
+    e = new IllegalStateException("Error", e);
+    when(cli.isDisplayStackTrace()).thenReturn(true);
+
+    EmbeddedRunner runner = mock(EmbeddedRunner.class);
+    doThrow(e).when(runner).runAnalysis(any(Properties.class));
+    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
+
+    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
+    main.execute();
+
+    verify(runner).stop();
+    verify(shutdown).exit(Exit.ERROR);
+    verify(logs).error("Error during Sonar runner execution", e);
+  }
+
+  @Test
+  public void should_not_stop_on_error_in_interactive_mode() throws Exception {
+    EmbeddedRunner runner = mock(EmbeddedRunner.class);
+    doThrow(new IllegalStateException("Error")).when(runner).runAnalysis(any(Properties.class));
+    when(runnerFactory.create(any(Properties.class))).thenReturn(runner);
+    when(cli.isInteractive()).thenReturn(true);
+
+    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
+    BufferedReader inputReader = mock(BufferedReader.class);
+    when(inputReader.readLine()).thenReturn("");
+    when(shutdown.shouldExit()).thenReturn(false).thenReturn(true);
+    main.setInputReader(inputReader);
+    main.execute();
+
+    verify(runner, times(2)).runAnalysis(any(Properties.class));
+    verify(runner).stop();
+    verify(shutdown).exit(Exit.SUCCESS);
+  }
+
+  @Test
+  public void should_only_display_version() throws IOException {
+
+    Properties p = new Properties();
+    when(cli.isDisplayVersionOnly()).thenReturn(true);
+    when(conf.properties()).thenReturn(p);
+
+    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
+    main.execute();
+
+    InOrder inOrder = Mockito.inOrder(shutdown, runnerFactory);
+
+    inOrder.verify(shutdown, times(1)).exit(Exit.SUCCESS);
+    inOrder.verify(runnerFactory, times(1)).create(p);
+    inOrder.verify(shutdown, times(1)).exit(Exit.SUCCESS);
+  }
+
+  @Test(timeout = 30000)
+  public void test_interactive_mode() throws IOException {
+    String inputStr = "qwe" + System.lineSeparator() + "qwe" + System.lineSeparator();
+    InputStream input = new ByteArrayInputStream(inputStr.getBytes(StandardCharsets.UTF_8));
+    System.setIn(input);
+    input.close();
+
+    when(cli.isInteractive()).thenReturn(true);
+    when(cli.isDebugMode()).thenReturn(true);
+    when(cli.isDisplayStackTrace()).thenReturn(true);
+
+    Main main = new Main(shutdown, cli, conf, runnerFactory, logs);
+    main.execute();
+
+    verify(runner, times(1)).start();
+    verify(runner, times(3)).runAnalysis(any(Properties.class));
+    verify(runner, times(1)).stop();
+  }
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/RunnerFactoryTest.java b/src/test/java/org/sonarsource/scanner/cli/RunnerFactoryTest.java
new file mode 100644 (file)
index 0000000..1caf5d5
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import org.sonar.runner.api.LogOutput.Level;
+import org.sonarsource.scanner.cli.Logs;
+import org.sonarsource.scanner.cli.RunnerFactory;
+import org.sonar.runner.api.LogOutput;
+import org.junit.Before;
+
+import java.util.Properties;
+
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.mock;
+import org.junit.Test;
+import org.sonar.runner.api.EmbeddedRunner;
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RunnerFactoryTest {
+
+  Properties props = new Properties();
+  Logs logs;
+
+  @Before
+  public void setUp() {
+    logs = mock(Logs.class);
+  }
+
+  @Test
+  public void should_create_embedded_runner() {
+    props.setProperty("foo", "bar");
+    EmbeddedRunner runner = new RunnerFactory(logs).create(props);
+
+    assertThat(runner).isInstanceOf(EmbeddedRunner.class);
+    assertThat(runner.globalProperties().get("foo")).isEqualTo("bar");
+  }
+
+  @Test
+  public void should_fwd_logs() {
+    LogOutput logOutput = new RunnerFactory(logs).new DefaultLogOutput();
+
+    String msg = "test";
+
+    logOutput.log(msg, Level.DEBUG);
+    verify(logs).debug(msg);
+    verifyNoMoreInteractions(logs);
+    reset(logs);
+
+    logOutput.log(msg, Level.INFO);
+    verify(logs).info(msg);
+    verifyNoMoreInteractions(logs);
+    reset(logs);
+
+    logOutput.log(msg, Level.ERROR);
+    verify(logs).error(msg);
+    verifyNoMoreInteractions(logs);
+    reset(logs);
+
+    logOutput.log(msg, Level.WARN);
+    verify(logs).info(msg);
+    verifyNoMoreInteractions(logs);
+    reset(logs);
+
+    logOutput.log(msg, Level.TRACE);
+    verify(logs).debug(msg);
+    verifyNoMoreInteractions(logs);
+    reset(logs);
+  }
+
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/ShutdownTest.java b/src/test/java/org/sonarsource/scanner/cli/ShutdownTest.java
new file mode 100644 (file)
index 0000000..0d6b3ba
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import com.jayway.awaitility.Duration;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.sonarsource.scanner.cli.Exit;
+import org.sonarsource.scanner.cli.Shutdown;
+
+import static com.jayway.awaitility.Awaitility.await;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.verify;
+
+public class ShutdownTest {
+  @Mock
+  private Exit exit;
+  private Shutdown shutdown;
+
+  @Before
+  public void setUp() {
+    MockitoAnnotations.initMocks(this);
+    shutdown = new Shutdown(exit, true);
+  }
+
+  @Test
+  public void testShutdown() {
+    shutdown.exit(3);
+    verify(exit).exit(3);
+  }
+
+  @Test(timeout = 60_000)
+  public void testWaitReady() throws InterruptedException {
+    shutdown = new Shutdown(exit, true, 100_000);
+    shutdown.signalReady(false);
+    assertThat(shutdown.shouldExit()).isFalse();
+
+    final Thread t = new HookCaller();
+    t.start();
+
+    await().atMost(Duration.TWO_SECONDS).pollDelay(50, TimeUnit.MILLISECONDS).until(new Callable<Boolean>() {
+      @Override
+      public Boolean call() throws Exception {
+        return t.isAlive();
+      }
+    });
+
+    assertThat(shutdown.shouldExit()).isTrue();
+
+    shutdown.signalReady(true);
+    t.join();
+  }
+
+  @Test(timeout = 60_000)
+  public void testTimeout() throws InterruptedException {
+    shutdown = new Shutdown(exit, true, 0);
+
+    Thread t = new HookCaller();
+    t.start();
+    t.join();
+  }
+
+  private class HookCaller extends Thread {
+    @Override
+    public void run() {
+      shutdown.hook.run();
+    }
+  }
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/StatsTest.java b/src/test/java/org/sonarsource/scanner/cli/StatsTest.java
new file mode 100644 (file)
index 0000000..2d0034e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import org.mockito.Mockito;
+import org.sonarsource.scanner.cli.Logs;
+import org.sonarsource.scanner.cli.Stats;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.mock;
+import org.junit.Test;
+import static org.fest.assertions.Assertions.assertThat;
+
+public class StatsTest {
+  private PrintStream stdOut = mock(PrintStream.class);
+  private PrintStream stdErr;
+  private Logs logs = new Logs(stdOut, stdErr);
+
+  @Test
+  public void shouldPrintStats() throws UnsupportedEncodingException {
+    new Stats(logs).start().stop();
+
+    verify(stdOut).println(Mockito.contains("Total time: "));
+    verify(stdOut).println(Mockito.contains("Final Memory: "));
+  }
+
+  @Test
+  public void shouldFormatTime() {
+    assertThat(Stats.formatTime(1 * 60 * 60 * 1000 + 2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("1:02:03.400s");
+    assertThat(Stats.formatTime(2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("2:03.400s");
+    assertThat(Stats.formatTime(3 * 1000 + 400)).isEqualTo("3.400s");
+    assertThat(Stats.formatTime(400)).isEqualTo("0.400s");
+  }
+}
diff --git a/src/test/java/org/sonarsource/scanner/cli/SystemInfoTest.java b/src/test/java/org/sonarsource/scanner/cli/SystemInfoTest.java
new file mode 100644 (file)
index 0000000..67bbf35
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube Scanner
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.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  02
+ */
+package org.sonarsource.scanner.cli;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import org.sonar.runner.api.RunnerVersion;
+import org.sonarsource.scanner.cli.Logs;
+import org.sonarsource.scanner.cli.SystemInfo;
+import org.sonarsource.scanner.cli.SystemInfo.System2;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class SystemInfoTest {
+  System2 mockSystem;
+  Logs logs;
+
+  @Before
+  public void setUp() {
+    mockSystem = mock(System2.class);
+    logs = mock(Logs.class);
+    SystemInfo.setSystem(mockSystem);
+  }
+
+  @Test
+  public void test_java() {
+    mockJava();
+    assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle (64-bit)");
+
+    when(mockSystem.getProperty("sun.arch.data.model")).thenReturn("32");
+    assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle (32-bit)");
+
+    when(mockSystem.getProperty("sun.arch.data.model")).thenReturn(null);
+    assertThat(SystemInfo.java()).isEqualTo("Java 1.9 oracle");
+  }
+
+  @Test
+  public void test_os() {
+    mockOs();
+
+    assertThat(SystemInfo.os()).isEqualTo("linux 2.5 x64");
+  }
+
+  private void mockJava() {
+    when(mockSystem.getProperty("java.version")).thenReturn("1.9");
+    when(mockSystem.getProperty("java.vendor")).thenReturn("oracle");
+    when(mockSystem.getProperty("sun.arch.data.model")).thenReturn("64");
+  }
+
+  private void mockOs() {
+    when(mockSystem.getProperty("os.version")).thenReturn("2.5");
+    when(mockSystem.getProperty("os.arch")).thenReturn("x64");
+    when(mockSystem.getProperty("os.name")).thenReturn("linux");
+  }
+
+  @Test
+  public void should_print() {
+    mockOs();
+    mockJava();
+    when(mockSystem.getenv("SONAR_RUNNER_OPTS")).thenReturn("arg");
+
+    SystemInfo.print(logs);
+
+    verify(mockSystem).getProperty("java.version");
+    verify(mockSystem).getProperty("os.version");
+    verify(mockSystem).getenv("SONAR_RUNNER_OPTS");
+
+    verify(logs).info("SonarQube Runner " + RunnerVersion.version());
+    verify(logs).info("Java 1.9 oracle (64-bit)");
+    verify(logs).info("linux 2.5 x64");
+    verify(logs).info("SONAR_RUNNER_OPTS=arg");
+    verifyNoMoreInteractions(logs);
+  }
+}
diff --git a/src/test/resources/org/sonar/runner/ConfTest/emptyModules/project/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/emptyModules/project/sonar-project.properties
deleted file mode 100644 (file)
index 708db4c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sonar.modules=
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/project/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/project/sonar-project.properties
deleted file mode 100644 (file)
index 0d1e025..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-project.prop=foo
-
-# overridden property
-overridden.prop=project scope
\ No newline at end of file
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/runner/conf/sonar-runner.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadCompleteConfiguration/runner/conf/sonar-runner.properties
deleted file mode 100644 (file)
index 7edfb99..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-overridden.prop=runner scope
-global.prop=jdbc:mysql:localhost/sonar
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties
deleted file mode 100644 (file)
index 6803263..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sonar.projectName=Module 1
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties
deleted file mode 100644 (file)
index c12fad8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sonar.projectName=Module 2
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties
deleted file mode 100644 (file)
index 835124c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sonar.modules=module1,module2
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module2.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module2.properties
deleted file mode 100644 (file)
index 4df820c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-sonar.projectName=Module 2
-sonar.projectBaseDir=module_2
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_1/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_1/sonar-project.properties
deleted file mode 100644 (file)
index 6803263..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sonar.projectName=Module 1
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_2/Sample.js b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_2/Sample.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_3/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_3/sonar-project.properties
deleted file mode 100644 (file)
index c074231..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sonar.projectName=Module 3
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/sonar-project.properties
deleted file mode 100644 (file)
index 999b04c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-sonar.modules=module1,module2,module3
-module1.sonar.projectBaseDir=module_1
-module2.sonar.projectConfigFile=module2.properties
-module3.sonar.projectConfigFile=module_3/sonar-project.properties
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties
deleted file mode 100644 (file)
index 33dc79b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-sonar.prop=otherValue
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByHome/conf/sonar-runner.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldLoadRunnerSettingsByHome/conf/sonar-runner.properties
deleted file mode 100644 (file)
index 1e03622..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-sonar.prop=value
-sonar.jdbc.url=jdbc:mysql:localhost/sonar
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module111/placeholder.txt b/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module111/placeholder.txt
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module112/placeholder.txt b/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module112/placeholder.txt
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module12/placeholder.txt b/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module12/placeholder.txt
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module21/placeholder.txt b/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module21/placeholder.txt
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module22/placeholder.txt b/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module22/placeholder.txt
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/sonar-project.properties b/src/test/resources/org/sonar/runner/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/sonar-project.properties
deleted file mode 100644 (file)
index 56eb032..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-sonar.modules=1,2
-1.sonar.projectName=Module 1
-1.sonar.projectBaseDir=module1
-1.sonar.modules=11,12
-1.11.sonar.projectBaseDir=module11
-1.11.sonar.projectName=Module 11
-1.11.sonar.modules=111,112
-1.11.111.sonar.projectBaseDir=module111
-1.11.111.sonar.projectName=Module 111
-1.11.112.sonar.projectBaseDir=module112
-1.11.112.sonar.projectName=Module 112
-
-1.12.sonar.projectBaseDir=module12
-1.12.sonar.projectName=Module 12
-
-2.sonar.projectName=Module 2
-2.sonar.projectBaseDir=module2
\ No newline at end of file
diff --git a/src/test/resources/org/sonar/runner/RunnerTest/shouldInitDirs/fake.txt b/src/test/resources/org/sonar/runner/RunnerTest/shouldInitDirs/fake.txt
deleted file mode 100644 (file)
index f0f877c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-fake
\ No newline at end of file
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/emptyModules/project/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/emptyModules/project/sonar-project.properties
new file mode 100644 (file)
index 0000000..708db4c
--- /dev/null
@@ -0,0 +1 @@
+sonar.modules=
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadCompleteConfiguration/project/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadCompleteConfiguration/project/sonar-project.properties
new file mode 100644 (file)
index 0000000..0d1e025
--- /dev/null
@@ -0,0 +1,4 @@
+project.prop=foo
+
+# overridden property
+overridden.prop=project scope
\ No newline at end of file
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadCompleteConfiguration/runner/conf/sonar-runner.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadCompleteConfiguration/runner/conf/sonar-runner.properties
new file mode 100644 (file)
index 0000000..7edfb99
--- /dev/null
@@ -0,0 +1,2 @@
+overridden.prop=runner scope
+global.prop=jdbc:mysql:localhost/sonar
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfiguration/project/module1/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/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/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfiguration/project/module2/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/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/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfiguration/project/sonar-project.properties
new file mode 100644 (file)
index 0000000..835124c
--- /dev/null
@@ -0,0 +1 @@
+sonar.modules=module1,module2
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module2.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module2.properties
new file mode 100644 (file)
index 0000000..4df820c
--- /dev/null
@@ -0,0 +1,2 @@
+sonar.projectName=Module 2
+sonar.projectBaseDir=module_2
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_1/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_1/sonar-project.properties
new file mode 100644 (file)
index 0000000..6803263
--- /dev/null
@@ -0,0 +1 @@
+sonar.projectName=Module 1
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_2/Sample.js b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_2/Sample.js
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_3/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/module_3/sonar-project.properties
new file mode 100644 (file)
index 0000000..c074231
--- /dev/null
@@ -0,0 +1 @@
+sonar.projectName=Module 3
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadModuleConfigurationOverrideBasedir/project/sonar-project.properties
new file mode 100644 (file)
index 0000000..999b04c
--- /dev/null
@@ -0,0 +1,4 @@
+sonar.modules=module1,module2,module3
+module1.sonar.projectBaseDir=module_1
+module2.sonar.projectConfigFile=module2.properties
+module3.sonar.projectConfigFile=module_3/sonar-project.properties
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadRunnerSettingsByDirectPath/other-conf.properties
new file mode 100644 (file)
index 0000000..33dc79b
--- /dev/null
@@ -0,0 +1 @@
+sonar.prop=otherValue
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadRunnerSettingsByHome/conf/sonar-runner.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldLoadRunnerSettingsByHome/conf/sonar-runner.properties
new file mode 100644 (file)
index 0000000..1e03622
--- /dev/null
@@ -0,0 +1,2 @@
+sonar.prop=value
+sonar.jdbc.url=jdbc:mysql:localhost/sonar
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module111/placeholder.txt b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module111/placeholder.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module112/placeholder.txt b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module11/module112/placeholder.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module12/placeholder.txt b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module1/module12/placeholder.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module21/placeholder.txt b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module21/placeholder.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module22/placeholder.txt b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/module2/module22/placeholder.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/sonar-project.properties b/src/test/resources/org/sonarsource/scanner/cli/ConfTest/shouldSupportDeepModuleConfigurationInRoot/project/sonar-project.properties
new file mode 100644 (file)
index 0000000..56eb032
--- /dev/null
@@ -0,0 +1,17 @@
+sonar.modules=1,2
+1.sonar.projectName=Module 1
+1.sonar.projectBaseDir=module1
+1.sonar.modules=11,12
+1.11.sonar.projectBaseDir=module11
+1.11.sonar.projectName=Module 11
+1.11.sonar.modules=111,112
+1.11.111.sonar.projectBaseDir=module111
+1.11.111.sonar.projectName=Module 111
+1.11.112.sonar.projectBaseDir=module112
+1.11.112.sonar.projectName=Module 112
+
+1.12.sonar.projectBaseDir=module12
+1.12.sonar.projectName=Module 12
+
+2.sonar.projectName=Module 2
+2.sonar.projectBaseDir=module2
\ No newline at end of file
diff --git a/src/test/resources/org/sonarsource/scanner/cli/RunnerTest/shouldInitDirs/fake.txt b/src/test/resources/org/sonarsource/scanner/cli/RunnerTest/shouldInitDirs/fake.txt
new file mode 100644 (file)
index 0000000..f0f877c
--- /dev/null
@@ -0,0 +1 @@
+fake
\ No newline at end of file