<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>
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
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"
-classpath $JAR_FILE \
"-Drunner.home=\${SONAR_RUNNER_HOME}" \
"-Dproject.home=\${PROJECT_HOME}" \
- org.sonar.runner.cli.Main "$@"
+ org.sonarsource.scanner.cli.Main "$@"
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
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
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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()]);
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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.");
- }
-
-}
+++ /dev/null
-/*
- * 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);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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
- }
- }
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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;
-
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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()]);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.");
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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");
- }
-
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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();
- }
- }
-}
+++ /dev/null
-/*
- * 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");
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
--- /dev/null
+/*
+ * 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");
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
+++ /dev/null
-sonar.modules=
+++ /dev/null
-project.prop=foo
-
-# overridden property
-overridden.prop=project scope
\ No newline at end of file
+++ /dev/null
-overridden.prop=runner scope
-global.prop=jdbc:mysql:localhost/sonar
+++ /dev/null
-sonar.projectName=Module 1
+++ /dev/null
-sonar.projectName=Module 2
+++ /dev/null
-sonar.modules=module1,module2
+++ /dev/null
-sonar.projectName=Module 2
-sonar.projectBaseDir=module_2
+++ /dev/null
-sonar.projectName=Module 1
+++ /dev/null
-sonar.projectName=Module 3
+++ /dev/null
-sonar.modules=module1,module2,module3
-module1.sonar.projectBaseDir=module_1
-module2.sonar.projectConfigFile=module2.properties
-module3.sonar.projectConfigFile=module_3/sonar-project.properties
+++ /dev/null
-sonar.prop=otherValue
+++ /dev/null
-sonar.prop=value
-sonar.jdbc.url=jdbc:mysql:localhost/sonar
+++ /dev/null
-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
+++ /dev/null
-fake
\ No newline at end of file
--- /dev/null
+sonar.modules=
--- /dev/null
+project.prop=foo
+
+# overridden property
+overridden.prop=project scope
\ No newline at end of file
--- /dev/null
+overridden.prop=runner scope
+global.prop=jdbc:mysql:localhost/sonar
--- /dev/null
+sonar.projectName=Module 1
--- /dev/null
+sonar.projectName=Module 2
--- /dev/null
+sonar.modules=module1,module2
--- /dev/null
+sonar.projectName=Module 2
+sonar.projectBaseDir=module_2
--- /dev/null
+sonar.projectName=Module 1
--- /dev/null
+sonar.projectName=Module 3
--- /dev/null
+sonar.modules=module1,module2,module3
+module1.sonar.projectBaseDir=module_1
+module2.sonar.projectConfigFile=module2.properties
+module3.sonar.projectConfigFile=module_3/sonar-project.properties
--- /dev/null
+sonar.prop=otherValue
--- /dev/null
+sonar.prop=value
+sonar.jdbc.url=jdbc:mysql:localhost/sonar
--- /dev/null
+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
--- /dev/null
+fake
\ No newline at end of file