Browse Source

SONARUNNER-138 Allow to redirect logs to a custom stream

tags/2.5-rc1
Duarte Meneses 9 years ago
parent
commit
f2e74b6d69
24 changed files with 458 additions and 162 deletions
  1. 4
    3
      sonar-runner-api/src/main/java/org/sonar/runner/api/CommandExecutor.java
  2. 23
    5
      sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java
  3. 27
    12
      sonar-runner-api/src/main/java/org/sonar/runner/api/ForkedRunner.java
  4. 14
    2
      sonar-runner-api/src/main/java/org/sonar/runner/api/Runner.java
  5. 11
    1
      sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java
  6. 46
    0
      sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java
  7. 39
    14
      sonar-runner-api/src/test/java/org/sonar/runner/api/ForkedRunnerTest.java
  8. 0
    1
      sonar-runner-api/src/test/java/org/sonar/runner/api/OsTest.java
  9. 11
    1
      sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java
  10. 9
    1
      sonar-runner-batch-interface/pom.xml
  11. 11
    1
      sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java
  12. 1
    1
      sonar-runner-batch/pom.xml
  13. 34
    37
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java
  14. 0
    28
      sonar-runner-batch/src/main/java/org/sonar/runner/batch/package-info.java
  15. 1
    31
      sonar-runner-batch/src/test/java/org/sonar/runner/batch/IsolatedLauncherTest.java
  16. 4
    2
      sonar-runner-dist/src/main/java/org/sonar/runner/Stats.java
  17. 6
    4
      sonar-runner-dist/src/main/java/org/sonar/runner/SystemInfo.java
  18. 15
    8
      sonar-runner-dist/src/test/java/org/sonar/runner/StatsTest.java
  19. 5
    0
      sonar-runner-impl/pom.xml
  20. 6
    2
      sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncherMain.java
  21. 1
    1
      sonar-runner-impl/src/main/java/org/sonar/runner/impl/IsolatedLauncherFactory.java
  22. 70
    7
      sonar-runner-impl/src/main/java/org/sonar/runner/impl/Logs.java
  23. 14
    0
      sonar-runner-impl/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java
  24. 106
    0
      sonar-runner-impl/src/test/java/org/sonar/runner/impl/LogsTest.java

+ 4
- 3
sonar-runner-api/src/main/java/org/sonar/runner/api/CommandExecutor.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.runner.api;

import org.sonar.runner.impl.Logs;

import javax.annotation.Nullable;

import java.io.BufferedReader;
@@ -101,7 +103,7 @@ class CommandExecutor {
}
}

private void monitorProcess(final ProcessMonitor processMonitor, final ExecutorService executor, final Process process) {
private static void monitorProcess(final ProcessMonitor processMonitor, final ExecutorService executor, final Process process) {
new Thread() {
@Override
public void run() {
@@ -149,8 +151,7 @@ class CommandExecutor {
try {
thread.join();
} catch (InterruptedException e) {
System.err.println("InterruptedException while waiting finish of " + thread.toString());
e.printStackTrace();
Logs.error("InterruptedException while waiting finish of " + thread.toString(), e);
}
}
}

+ 23
- 5
sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java View File

@@ -19,13 +19,15 @@
*/
package org.sonar.runner.api;

import org.sonar.home.log.LogListener;

import org.sonar.runner.impl.Logs;
import org.sonar.runner.batch.IsolatedLauncher;
import org.sonar.runner.impl.IsolatedLauncherFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
@@ -36,9 +38,9 @@ import java.util.Properties;
* @since 2.2
*/
public class EmbeddedRunner extends Runner<EmbeddedRunner> {

private final IsolatedLauncherFactory launcherFactory;
private IsolatedLauncher launcher;
private String sqVersion;
private final List<Object> extensions = new ArrayList<Object>();
private static final String MASK_RULES_PROP = "sonarRunner.maskRules";

@@ -53,6 +55,11 @@ public class EmbeddedRunner extends Runner<EmbeddedRunner> {
return new EmbeddedRunner(new IsolatedLauncherFactory());
}

public static EmbeddedRunner create(LogListener logListener) {
Logs.setListener(logListener);
return new EmbeddedRunner(new IsolatedLauncherFactory());
}

/**
* Sonar is executed in an almost fully isolated classloader (mask everything by default). This method allows to unmask some classes based on
* a prefix of their fully qualified name. It is related to the extensions provided by {@link #addExtensions(Object...)}.
@@ -104,16 +111,27 @@ public class EmbeddedRunner extends Runner<EmbeddedRunner> {
@Override
protected void doStart() {
launcher = launcherFactory.createLauncher(globalProperties());
launcher.start(globalProperties(), extensions);
if (Utils.isAtLeast52(launcher.getVersion())) {
launcher.start(globalProperties(), extensions, Logs.getListener());
}
}

@Override
protected void doStop() {
launcher.stop();
if (Utils.isAtLeast52(launcher.getVersion())) {
launcher.stop();
}
}

@Override
protected void doExecute(Properties analysisProperties) {
launcher.execute(analysisProperties);
if (Utils.isAtLeast52(launcher.getVersion())) {
launcher.execute(analysisProperties);
} else {
Properties prop = new Properties();
prop.putAll(globalProperties());
prop.putAll(analysisProperties);
launcher.executeOldVersion(prop, extensions);
}
}
}

+ 27
- 12
sonar-runner-api/src/main/java/org/sonar/runner/api/ForkedRunner.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.runner.api;

import org.sonar.runner.impl.Logs;
import org.sonar.runner.impl.BatchLauncherMain;
import org.sonar.runner.impl.JarExtractor;

@@ -46,7 +47,8 @@ public class ForkedRunner extends Runner<ForkedRunner> {
private final Map<String, String> jvmEnvVariables = new HashMap<String, String>();
private final List<String> jvmArguments = new ArrayList<String>();
private String javaExecutable;
private StreamConsumer stdOut = null, stdErr = null;
private StreamConsumer stdOut = null;
private StreamConsumer stdErr = null;
private final JarExtractor jarExtractor;
private final CommandExecutor commandExecutor;

@@ -121,7 +123,8 @@ public class ForkedRunner extends Runner<ForkedRunner> {
}

/**
* Subscribe to the standard output. By default output is {@link System.out}
* @deprecated Since 2.5. Use {@link ForkedRunner#setLogListener} instead.
* Subscribe to the standard output from the forked process. By default, logs messages are sent with INFO level to the log listener set.
*/
public ForkedRunner setStdOut(@Nullable StreamConsumer stream) {
this.stdOut = stream;
@@ -129,7 +132,8 @@ public class ForkedRunner extends Runner<ForkedRunner> {
}

/**
* Subscribe to the error output. By default output is {@link System.err}
* @deprecated Since 2.5. Use {@link ForkedRunner#setLogListener}instead.
* Subscribe to the error output from the forked process. By default, logs messages are sent with ERROR level to the log listener set.
*/
public ForkedRunner setStdErr(@Nullable StreamConsumer stream) {
this.stdErr = stream;
@@ -138,12 +142,12 @@ public class ForkedRunner extends Runner<ForkedRunner> {

@Override
protected void doExecute(Properties props) {
//merge both global and analysis-specific properties because it will be used both to start and to execute.
// merge both global and analysis-specific properties because it will be used both to start and to execute.
Properties p = new Properties();
p.putAll(globalProperties());
p.putAll(props);
ForkCommand forkCommand = createCommand(p);
try {
fork(forkCommand);
@@ -151,15 +155,15 @@ public class ForkedRunner extends Runner<ForkedRunner> {
deleteTempFiles(forkCommand);
}
}
@Override
protected void doStop() {
//nothing to do
// nothing to do
}
@Override
protected void doStart() {
//nothing to do
// nothing to do
}

ForkCommand createCommand(Properties p) {
@@ -196,11 +200,22 @@ public class ForkedRunner extends Runner<ForkedRunner> {

private void fork(ForkCommand forkCommand) {
if (stdOut == null) {
stdOut = new PrintStreamConsumer(System.out);
stdOut = new StreamConsumer() {
@Override
public void consumeLine(String line) {
Logs.info(line);
}
};
}
if (stdErr == null) {
stdErr = new PrintStreamConsumer(System.err);
stdErr = new StreamConsumer() {
@Override
public void consumeLine(String line) {
Logs.error(line);
}
};
}

int status = commandExecutor.execute(forkCommand.command, stdOut, stdErr, ONE_DAY_IN_MILLISECONDS, processMonitor);
if (status != 0) {
if (processMonitor != null && processMonitor.stop()) {

+ 14
- 2
sonar-runner-api/src/main/java/org/sonar/runner/api/Runner.java View File

@@ -19,6 +19,9 @@
*/
package org.sonar.runner.api;

import org.sonar.home.log.LogListener;

import org.sonar.runner.impl.Logs;
import org.sonar.runner.impl.InternalProperties;

import javax.annotation.Nullable;
@@ -30,7 +33,6 @@ import java.util.Properties;
* @since 2.2
*/
public abstract class Runner<T extends Runner> {

private final Properties globalProperties = new Properties();

protected Runner() {
@@ -41,6 +43,16 @@ public abstract class Runner<T extends Runner> {
clone.putAll(globalProperties);
return clone;
}
/**
* Set a log stream. All log events will be redirected to the listener.
* By default, all logs are sent to stdout, except for logs of ERROR level, which are sent to stderr.
* If null is given, the default is behavior is set.
*/
public T setLogListener(LogListener stream) {
Logs.setListener(stream);
return (T) this;
}

/**
* Declare Sonar properties, for example sonar.projectKey=>foo.
@@ -93,7 +105,7 @@ public abstract class Runner<T extends Runner> {
if (dumpToFile != null) {
File dumpFile = new File(dumpToFile);
Utils.writeProperties(dumpFile, copy);
System.out.println("Simulation mode. Configuration written to " + dumpFile.getAbsolutePath());
Logs.info("Simulation mode. Configuration written to " + dumpFile.getAbsolutePath());
} else {
doExecute(copy);
}

+ 11
- 1
sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java View File

@@ -33,12 +33,22 @@ import java.nio.file.SimpleFileVisitor;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Properties;
import java.nio.file.attribute.*;
import java.nio.file.attribute.BasicFileAttributes;

class Utils {
private Utils() {
// only util static methods
}
static boolean isAtLeast52(String version) {
//it can be snapshot (5.2-SNAPSHOT)
if(version == null) {
return false;
}
int endIndex = Math.min(3, version.length());
return Double.parseDouble(version.substring(0, endIndex)) >= 5.2;
}

/**
* Similar to org.apache.commons.lang.StringUtils#join()

+ 46
- 0
sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java View File

@@ -31,8 +31,11 @@ import org.sonar.runner.impl.InternalProperties;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.any;
import static org.fest.assertions.Assertions.assertThat;
@@ -58,6 +61,7 @@ public class EmbeddedRunnerTest {
public void setUp() {
batchLauncher = mock(IsolatedLauncherFactory.class);
launcher = mock(IsolatedLauncher.class);
when(launcher.getVersion()).thenReturn("5.2");
when(batchLauncher.createLauncher(any(Properties.class))).thenReturn(launcher);
runner = new EmbeddedRunner(batchLauncher);
}
@@ -68,6 +72,48 @@ public class EmbeddedRunnerTest {
assertThat(runner.app()).isEqualTo("Eclipse");
assertThat(runner.appVersion()).isEqualTo("3.1");
}
@Test
public void test_back_compatibility() {
when(launcher.getVersion()).thenReturn("4.5");
final FakeExtension fakeExtension = new FakeExtension();
List<Object> extensionList = new LinkedList<>();
extensionList.add(fakeExtension);
Properties analysisProps = new Properties();
analysisProps.put("sonar.dummy", "summy");
runner.addExtensions(fakeExtension);
runner.setGlobalProperty("sonar.projectKey", "foo");
runner.start();
runner.runAnalysis(analysisProps);
runner.stop();

verify(batchLauncher).createLauncher(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
return "foo".equals(((Properties) o).getProperty("sonar.projectKey"));
}
}));

// it should have added a few properties to analysisProperties, and have merged global props
final String[] mustHaveKeys = {"sonar.working.directory", "sonar.sourceEncoding", "sonar.projectBaseDir",
"sonar.projectKey", "sonar.dummy"};

verify(launcher).executeOldVersion(argThat(new ArgumentMatcher<Properties>() {
@Override
public boolean matches(Object o) {
Properties m = (Properties) o;
for (String s : mustHaveKeys) {
if (!m.containsKey(s)) {
return false;
}
}
return true;
}
}), eq(extensionList));
}

@Test
public void should_set_unmasked_packages() {

+ 39
- 14
sonar-runner-api/src/test/java/org/sonar/runner/api/ForkedRunnerTest.java View File

@@ -19,8 +19,10 @@
*/
package org.sonar.runner.api;

import org.sonar.home.log.LogListener.Level;
import org.sonar.home.log.LogListener;
import org.sonar.runner.impl.Logs;
import org.mockito.Mockito;

import org.mockito.ArgumentCaptor;
import org.junit.Before;
import org.junit.Rule;
@@ -29,12 +31,16 @@ import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentMatcher;
import org.sonar.runner.impl.JarExtractor;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
import static org.mockito.Matchers.any;
@@ -74,27 +80,46 @@ public class ForkedRunnerTest {
}

@Test
public void should_print_to_standard_outputs_by_default() throws IOException {
public void should_use_log_listener() throws IOException {
JarExtractor jarExtractor = createMockExtractor();

CommandExecutor commandExecutor = mock(CommandExecutor.class);
ForkedRunner runner = new ForkedRunner(jarExtractor, commandExecutor);
runner.execute();

verify(commandExecutor).execute(any(Command.class), argThat(new StdConsumerMatcher(System.out)), argThat(new StdConsumerMatcher(System.err)), anyLong(),
any(ProcessMonitor.class));
LogListener listener = mock(LogListener.class);
Logs.setListener(listener);

ArgumentCaptor<StreamConsumer> arg1 = ArgumentCaptor.forClass(StreamConsumer.class);
ArgumentCaptor<StreamConsumer> arg2 = ArgumentCaptor.forClass(StreamConsumer.class);
verify(commandExecutor).execute(any(Command.class), arg1.capture(), arg2.capture(), anyLong(), any(ProcessMonitor.class));
arg1.getValue().consumeLine("test1");
arg2.getValue().consumeLine("test2");
verify(listener).log("test1", Level.INFO);
verify(listener).log("test2", Level.ERROR);
verifyNoMoreInteractions(listener);
}
@Test
public void should_print_to_consumers_by_default() throws IOException {
final List<String> printedLines = new LinkedList<>();
StreamConsumer consumer = new StreamConsumer() {
@Override
public void consumeLine(String line) {
printedLines.add(line);
}
};
JarExtractor jarExtractor = createMockExtractor();

static class StdConsumerMatcher extends ArgumentMatcher<StreamConsumer> {
PrintStream output;

StdConsumerMatcher(PrintStream output) {
this.output = output;
}
CommandExecutor commandExecutor = mock(CommandExecutor.class);
ForkedRunner runner = new ForkedRunner(jarExtractor, commandExecutor);
runner.setStdOut(consumer);
runner.setStdErr(consumer);
runner.execute();

public boolean matches(Object o) {
return ((PrintStreamConsumer) o).output == output;
}
verify(commandExecutor).execute(any(Command.class), eq(consumer), eq(consumer), anyLong(),
any(ProcessMonitor.class));
}

@Test

+ 0
- 1
sonar-runner-api/src/test/java/org/sonar/runner/api/OsTest.java View File

@@ -40,7 +40,6 @@ public class OsTest {

@Test
public void testUsedJavaExe() throws Exception {
System.out.println(System.getProperty("java.io.tmpdir"));
File javaExe = new Os().thisJavaExe();
assertThat(javaExe).isNotNull().isFile().exists();
assertThat(javaExe.getName()).contains("java");

+ 11
- 1
sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java View File

@@ -41,6 +41,16 @@ public class UtilsTest {
assertThat(Utils.join(new String[] {"foo", "bar"}, ",")).isEqualTo("foo,bar");
}

@Test
public void parse_version() {
assertThat(Utils.isAtLeast52("5.2")).isTrue();
assertThat(Utils.isAtLeast52(null)).isFalse();
assertThat(Utils.isAtLeast52("52")).isTrue();
assertThat(Utils.isAtLeast52("5.0")).isFalse();
assertThat(Utils.isAtLeast52("6.0.0")).isTrue();
assertThat(Utils.isAtLeast52("5.2-SNAPSHOT")).isTrue();
}

@Test
public void task_should_require_project() {
Properties props = new Properties();
@@ -64,7 +74,7 @@ public class UtilsTest {
Utils.closeQuietly(c);
verify(c).close();
}
@Test
public void close_quietly_null() throws IOException {
Utils.closeQuietly(null);

+ 9
- 1
sonar-runner-batch-interface/pom.xml View File

@@ -7,5 +7,13 @@
</parent>

<artifactId>sonar-runner-batch-interface</artifactId>
<name>SonarQube Runner - Batch API</name>
<name>SonarQube Runner - Batch Interface</name>
<dependencies>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-home</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

+ 11
- 1
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java View File

@@ -1,5 +1,5 @@
/*
* SonarQube Runner - Batch API
* SonarQube Runner - Batch Interface
* Copyright (C) 2011 SonarSource
* dev@sonar.codehaus.org
*
@@ -19,11 +19,21 @@
*/
package org.sonar.runner.batch;

import org.sonar.home.log.LogListener;

import java.util.List;
import java.util.Properties;

public interface IsolatedLauncher {
void start(Properties properties, List<Object> extensions);

void start(Properties properties, List<Object> extensions, LogListener logListener);

void stop();

void execute(Properties properties);

void executeOldVersion(Properties properties, List<Object> extensions);

String getVersion();
}

+ 1
- 1
sonar-runner-batch/pom.xml View File

@@ -10,7 +10,7 @@
<name>SonarQube Runner - Batch</name>

<properties>
<sonarBatchVersion>4.4</sonarBatchVersion>
<sonarBatchVersion>5.2-SNAPSHOT</sonarBatchVersion>
</properties>

<dependencies>

+ 34
- 37
sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java View File

@@ -19,18 +19,19 @@
*/
package org.sonar.runner.batch;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import org.sonar.home.log.LogListener;
import org.picocontainer.annotations.Nullable;
import com.google.common.annotations.VisibleForTesting;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.slf4j.LoggerFactory;
import org.sonar.api.utils.SonarException;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
@@ -49,7 +50,12 @@ public class BatchIsolatedLauncher implements IsolatedLauncher {

@Override
public void start(Properties globalProperties, List<Object> extensions) {
batch = createBatch(globalProperties, extensions);
start(globalProperties, extensions, null);
}

@Override
public void start(Properties globalProperties, List<Object> extensions, @Nullable LogListener logListener) {
batch = createBatch(globalProperties, extensions, logListener);
batch.start();
}

@@ -63,47 +69,38 @@ public class BatchIsolatedLauncher implements IsolatedLauncher {
batch.executeTask((Map) properties);
}

Batch createBatch(Properties properties, List<Object> extensions) {
initLogging(properties);
Batch createBatch(Properties properties, List<Object> extensions, @Nullable LogListener logListener) {
EnvironmentInformation env = new EnvironmentInformation(properties.getProperty("sonarRunner.app"), properties.getProperty("sonarRunner.appVersion"));
return Batch.builder()
Batch.Builder builder = Batch.builder()
.setEnvironment(env)
.addComponents(extensions)
.setBootstrapProperties((Map) properties)
.build();
}
.setBootstrapProperties((Map) properties);

private void initLogging(Properties props) {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator jc = new JoranConfigurator();
jc.setContext(context);
context.reset();
try (InputStream input = Batch.class.getResourceAsStream("/org/sonar/batch/logback.xml")) {
System.setProperty("ROOT_LOGGER_LEVEL", isDebug(props) ? DEBUG : "INFO");
context.putProperty("SQL_LOGGER_LEVEL", getSqlLevel(props));
context.putProperty("SQL_RESULTS_LOGGER_LEVEL", getSqlResultsLevel(props));
jc.doConfigure(input);
} catch (JoranException e) {
throw new SonarException("can not initialize logging", e);
} catch (IOException e1) {
throw new SonarException("couldn't close resource", e1);
if (logListener != null) {
builder.setLogListener(logListener);
}
}

@VisibleForTesting
protected boolean isDebug(Properties props) {
return Boolean.parseBoolean(props.getProperty("sonar.verbose", FALSE));
return builder.build();
}

@VisibleForTesting
protected static String getSqlLevel(Properties props) {
boolean showSql = "true".equals(props.getProperty("sonar.showSql", FALSE));
return showSql ? DEBUG : WARN;
/**
* This method exists for backward compatibility with SonarQube < 5.2.
*/
@Override
public void executeOldVersion(Properties properties, List<Object> extensions) {
createBatch(properties, extensions, null).execute();
}

@VisibleForTesting
protected static String getSqlResultsLevel(Properties props) {
boolean showSql = "true".equals(props.getProperty("sonar.showSqlResults", FALSE));
return showSql ? DEBUG : WARN;
@Override
public String getVersion() {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sq-version.txt");
if (is == null) {
return null;
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
return br.readLine();
} catch (IOException e) {
return null;
}
}
}

+ 0
- 28
sonar-runner-batch/src/main/java/org/sonar/runner/batch/package-info.java View File

@@ -1,28 +0,0 @@
/*
* SonarQube Runner - Batch
* Copyright (C) 2011 SonarSource
* dev@sonar.codehaus.org
*
* 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
*/
/**
* Internal package that creates the project definition and launches the analyses based on it.
* Should not be used by consumers.
*/
@ParametersAreNonnullByDefault
package org.sonar.runner.batch;

import javax.annotation.ParametersAreNonnullByDefault;


+ 1
- 31
sonar-runner-batch/src/test/java/org/sonar/runner/batch/IsolatedLauncherTest.java View File

@@ -38,38 +38,8 @@ public class IsolatedLauncherTest {
props.setProperty("sonar.projectName", "Sample");
props.setProperty("sonar.projectVersion", "1.0");
props.setProperty("sonar.sources", "src");
Batch batch = launcher.createBatch(props, Collections.emptyList());
Batch batch = launcher.createBatch(props, Collections.emptyList(), null);

assertThat(batch).isNotNull();
}

@Test
public void testGetSqlLevel() throws Exception {
assertThat(BatchIsolatedLauncher.getSqlLevel(props)).isEqualTo("WARN");

props.setProperty("sonar.showSql", "true");
assertThat(BatchIsolatedLauncher.getSqlLevel(props)).isEqualTo("DEBUG");

props.setProperty("sonar.showSql", "false");
assertThat(BatchIsolatedLauncher.getSqlLevel(props)).isEqualTo("WARN");
}

@Test
public void testGetSqlResultsLevel() throws Exception {
assertThat(BatchIsolatedLauncher.getSqlResultsLevel(props)).isEqualTo("WARN");

props.setProperty("sonar.showSqlResults", "true");
assertThat(BatchIsolatedLauncher.getSqlResultsLevel(props)).isEqualTo("DEBUG");

props.setProperty("sonar.showSqlResults", "false");
assertThat(BatchIsolatedLauncher.getSqlResultsLevel(props)).isEqualTo("WARN");
}

@Test
public void shouldDetermineVerboseMode() {
assertThat(launcher.isDebug(props)).isFalse();

props.setProperty("sonar.verbose", "true");
assertThat(launcher.isDebug(props)).isTrue();
}
}

+ 4
- 2
sonar-runner-dist/src/main/java/org/sonar/runner/Stats.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.runner;

import org.sonar.runner.impl.Logs;

class Stats {
private long startTime;

@@ -32,12 +34,12 @@ class Stats {

Stats stop() {
long stopTime = System.currentTimeMillis() - startTime;
System.out.println("Total time: " + formatTime(stopTime));
Logs.info("Total time: " + formatTime(stopTime));

System.gc();
Runtime r = Runtime.getRuntime();
long mb = 1024L * 1024;
System.out.println("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M");
Logs.info("Final Memory: " + (r.totalMemory() - r.freeMemory()) / mb + "M/" + r.totalMemory() / mb + "M");

return this;
}

+ 6
- 4
sonar-runner-dist/src/main/java/org/sonar/runner/SystemInfo.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.runner;

import org.sonar.runner.impl.Logs;

import org.sonar.runner.api.RunnerVersion;

class SystemInfo {
@@ -28,12 +30,12 @@ class SystemInfo {
}

static void print() {
System.out.println("SonarQube Runner " + RunnerVersion.version());
System.out.println(java());
System.out.println(os());
Logs.info("SonarQube Runner " + RunnerVersion.version());
Logs.info(java());
Logs.info(os());
String runnerOpts = System.getenv("SONAR_RUNNER_OPTS");
if (runnerOpts != null) {
System.out.println("SONAR_RUNNER_OPTS=" + runnerOpts);
Logs.info("SONAR_RUNNER_OPTS=" + runnerOpts);
}
}


+ 15
- 8
sonar-runner-dist/src/test/java/org/sonar/runner/StatsTest.java View File

@@ -19,8 +19,10 @@
*/
package org.sonar.runner;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.sonar.home.log.LogListener;

import org.sonar.runner.impl.Logs;

import java.io.UnsupportedEncodingException;

import org.junit.Test;
@@ -31,17 +33,22 @@ public class StatsTest {

@Test
public void shouldPrintStats() throws UnsupportedEncodingException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));
final StringBuffer sb = new StringBuffer();
Logs.setListener(new LogListener() {
@Override
public void log(String msg, Level level) {
sb.append(msg + System.lineSeparator());
}
});
new Stats().start().stop();

String out = output.toString("UTF-8");
String[] lines = out.split("\n");
String out = sb.toString();
String[] lines = out.split(System.lineSeparator());
assertThat(lines).hasSize(2);
assertThat(lines[0]).startsWith("Total time: ");
assertThat(lines[1]).startsWith("Final Memory: ");
assertThat(lines[0]).contains("Total time: ");
assertThat(lines[1]).contains("Final Memory: ");
}

@Test

+ 5
- 0
sonar-runner-impl/pom.xml View File

@@ -123,6 +123,11 @@
<relocation>
<pattern>org.sonar.home</pattern>
<shadedPattern>org.sonar.runner.home</shadedPattern>
<!-- shared between sonar-runner-api, sonar-runner-impl and sonar-batch -->
<excludes>
<exclude>org.sonar.home.log.LogListener</exclude>
<exclude>org.sonar.home.log.LogListener$Level</exclude>
</excludes>
</relocation>
</relocations>
</configuration>

+ 6
- 2
sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncherMain.java View File

@@ -40,8 +40,12 @@ public class BatchLauncherMain {
Properties props = loadProperties(args[0]);
IsolatedLauncher launcher = launcherFactory.createLauncher(props);
launcher.start(props, Collections.emptyList());
launcher.execute(props);
launcher.stop();
try {
launcher.execute(props);
} finally {
//persistit has non-daemon threads that need to be stopped or the jvm w'ont quit
launcher.stop();
}
}

private static Properties loadProperties(String arg) throws IOException {

+ 1
- 1
sonar-runner-impl/src/main/java/org/sonar/runner/impl/IsolatedLauncherFactory.java View File

@@ -69,7 +69,7 @@ public class IsolatedLauncherFactory {
}

private static void addIsolatedLauncherMaskRule(Properties props) {
String unmask = "UNMASK|org.sonar.runner.batch.IsolatedLauncher";
String unmask = "UNMASK|org.sonar.runner.batch.IsolatedLauncher,UNMASK|org.sonar.home.log.LogListener";
String currentRules = (String) props.get(InternalProperties.RUNNER_MASK_RULES);

if (currentRules == null) {

+ 70
- 7
sonar-runner-impl/src/main/java/org/sonar/runner/impl/Logs.java View File

@@ -19,11 +19,37 @@
*/
package org.sonar.runner.impl;

import org.sonar.home.log.LogListener.Level;

import org.sonar.home.log.LogListener;

import javax.annotation.Nullable;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

public class Logs {
private static LogListener listener = new PrintStreamLogListener(getDefaultFwdMap());
private static boolean debugEnabled = false;

private Logs() {
}

private static boolean debugEnabled = false;
public static void setListener(@Nullable LogListener listener) {
if (listener == null) {
Logs.listener = new PrintStreamLogListener(getDefaultFwdMap());
} else {
Logs.listener = listener;
}
}

public static LogListener getListener() {
return Logs.listener;
}

public static void setDebugEnabled(boolean debugEnabled) {
Logs.debugEnabled = debugEnabled;
@@ -35,26 +61,63 @@ public class Logs {

public static void debug(String message) {
if (isDebugEnabled()) {
System.out.println("DEBUG: " + message);
log(message, Level.DEBUG);
}
}

public static void info(String message) {
System.out.println("INFO: " + message);
log(message, Level.INFO);
}

public static void warn(String message) {
System.out.println("WARN: " + message);
log(message, Level.WARN);
}

public static void error(String message) {
System.err.println("ERROR: " + message);
log(message, Level.ERROR);
}

public static void error(String message, Throwable t) {
System.err.println("ERROR: " + message);
log(message, Level.ERROR);
if (t != null) {
t.printStackTrace(System.err);
StringWriter sw = new StringWriter();

t.printStackTrace(new PrintWriter(sw));
String[] lines = sw.toString().split(System.getProperty("line.separator"));
for (String l : lines) {
log(l, Level.ERROR);
}
}
}

private static void log(String msg, Level level) {
listener.log(msg, level);
}

private static Map<Level, PrintStream> getDefaultFwdMap() {
Map<Level, PrintStream> map = new EnumMap<>(Level.class);

map.put(Level.ERROR, System.err);
map.put(Level.WARN, System.out);
map.put(Level.INFO, System.out);
map.put(Level.DEBUG, System.out);
map.put(Level.TRACE, System.out);
return map;
}

private static class PrintStreamLogListener implements LogListener {
Map<Level, PrintStream> forwardMap;

PrintStreamLogListener(Map<Level, PrintStream> forwardMap) {
this.forwardMap = new HashMap<>(forwardMap);
}

@Override
public void log(String msg, Level level) {
PrintStream ps = forwardMap.get(level);
if (ps != null) {
ps.append(level.toString() + ": " + msg + System.lineSeparator());
}
}
}
}

+ 14
- 0
sonar-runner-impl/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.runner.impl;

import org.sonar.home.log.LogListener;
import org.junit.Before;
import org.sonar.runner.batch.IsolatedLauncher;

@@ -102,5 +103,18 @@ public class IsolatedLauncherFactoryTest {
public void execute(Properties properties) {
FakeIsolatedLauncher.props = properties;
}

@Override
public void start(Properties properties, List<Object> extensions, LogListener logListener) {
}

@Override
public void executeOldVersion(Properties properties, List<Object> extensions) {
}

@Override
public String getVersion() {
return null;
}
}
}

+ 106
- 0
sonar-runner-impl/src/test/java/org/sonar/runner/impl/LogsTest.java View File

@@ -0,0 +1,106 @@
/*
* SonarQube Runner - Implementation
* Copyright (C) 2011 SonarSource
* dev@sonar.codehaus.org
*
* 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.impl;

import org.sonar.home.log.LogListener;

import org.junit.Test;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Before;

public class LogsTest {
private static final String EXPECTED_DEBUG = "DEBUG: debug\n";
private static final String EXPECTED_INFO = "INFO: info\n";
private static final String EXPECTED_ERROR = "ERROR: error\n";

private ByteArrayOutputStream recordedSystemOut = new ByteArrayOutputStream();
private ByteArrayOutputStream recordedSystemErr = new ByteArrayOutputStream();

@Before
public void restoreDefault() {
recordedSystemOut = new ByteArrayOutputStream();
recordedSystemErr = new ByteArrayOutputStream();

System.setOut(new PrintStream(recordedSystemOut));
System.setErr(new PrintStream(recordedSystemErr));

Logs.setDebugEnabled(false);
Logs.setListener(null);
}

@Test
public void testNull() throws UnsupportedEncodingException {
Logs.setListener(null);
testDefault();
}

@Test
public void testDefault() throws UnsupportedEncodingException {
writeTest();

assertThat(recordedSystemOut.toString(StandardCharsets.UTF_8.name())).isEqualTo(EXPECTED_INFO);
assertThat(recordedSystemErr.toString(StandardCharsets.UTF_8.name())).isEqualTo(EXPECTED_ERROR);
}

@Test
public void testDebug() throws UnsupportedEncodingException {
Logs.setDebugEnabled(true);
writeTest();

assertThat(recordedSystemOut.toString(StandardCharsets.UTF_8.name())).isEqualTo(EXPECTED_DEBUG + EXPECTED_INFO);
assertThat(recordedSystemErr.toString(StandardCharsets.UTF_8.name())).isEqualTo(EXPECTED_ERROR);
}

@Test
public void testCustomListener() {
TestLogListener listener = new TestLogListener();

Logs.setListener(listener);
Logs.setDebugEnabled(true);

Logs.debug("debug");

assertThat(listener.msg).isEqualTo("debug");
assertThat(listener.level).isEqualTo(LogListener.Level.DEBUG);
}

private class TestLogListener implements LogListener {
String msg;
Level level;

@Override
public void log(String msg, Level level) {
this.msg = msg;
this.level = level;
}
}

private static void writeTest() {
Logs.debug("debug");
Logs.info("info");
Logs.error("error");
}
}

Loading…
Cancel
Save