From 93217fe761c5fa51a695133f9c0358ddb66f68e1 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Thu, 28 May 2015 16:20:52 +0200 Subject: [PATCH] SONARUNNER-132 Add support for offline mode --- pom.xml | 11 +++- sonar-runner-api/pom.xml | 19 ++---- .../org/sonar/runner/api/CommandExecutor.java | 18 ++--- .../main/java/org/sonar/runner/api/Dirs.java | 3 +- .../org/sonar/runner/api/ForkedRunner.java | 18 ++--- .../java/org/sonar/runner/api/Runner.java | 7 +- .../main/java/org/sonar/runner/api/Utils.java | 57 +++++++++++++++- .../sonar/runner/api/CommandExecutorTest.java | 4 +- .../java/org/sonar/runner/api/DirsTest.java | 4 +- .../java/org/sonar/runner/api/UtilsTest.java | 54 ++++++++++++++- .../sonar/runner/batch/IsolatedLauncher.java | 19 +++--- sonar-runner-dist/pom.xml | 5 +- sonar-runner-impl/pom.xml | 4 ++ .../org/sonar/runner/impl/BatchLauncher.java | 16 ++++- .../sonar/runner/impl/BatchLauncherMain.java | 9 +-- .../main/java/org/sonar/runner/impl/Jars.java | 9 +-- .../sonar/runner/impl/ServerConnection.java | 63 +++++++++++++----- .../sonar/runner/impl/JarDownloaderTest.java | 2 +- .../java/org/sonar/runner/impl/JarsTest.java | 6 +- .../runner/impl/ServerConnectionTest.java | 65 +++++++++++++++++-- 20 files changed, 286 insertions(+), 107 deletions(-) diff --git a/pom.xml b/pom.xml index a71f58a..527cbc7 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.codehaus.sonar-plugins parent - 17 + 19 org.codehaus.sonar.runner @@ -104,6 +104,11 @@ commons-lang 2.6 + + commons-io + commons-io + 2.4 + org.easytesting fest-assert @@ -132,7 +137,7 @@ org.codehaus.sonar sonar-home - 3.5 + 5.2-SNAPSHOT @@ -148,7 +153,7 @@ org.apache.maven.plugins maven-shade-plugin - 1.7.1 + 2.3 diff --git a/sonar-runner-api/pom.xml b/sonar-runner-api/pom.xml index 84ea642..0f491c7 100644 --- a/sonar-runner-api/pom.xml +++ b/sonar-runner-api/pom.xml @@ -15,19 +15,18 @@ ${project.groupId} sonar-runner-impl ${project.version} + + + * + * + + com.google.code.findbugs jsr305 provided - - commons-io - commons-io - 2.0.1 - - provided - @@ -113,12 +112,6 @@ true true - - - org.apache.commons.io - org.sonar.runner.commonsio - - diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/api/CommandExecutor.java b/sonar-runner-api/src/main/java/org/sonar/runner/api/CommandExecutor.java index f54dbb9..999150d 100644 --- a/sonar-runner-api/src/main/java/org/sonar/runner/api/CommandExecutor.java +++ b/sonar-runner-api/src/main/java/org/sonar/runner/api/CommandExecutor.java @@ -19,8 +19,6 @@ */ package org.sonar.runner.api; -import org.apache.commons.io.IOUtils; - import javax.annotation.Nullable; import java.io.BufferedReader; @@ -136,10 +134,10 @@ class CommandExecutor { private void closeStreams(Process process) { if (process != null) { - IOUtils.closeQuietly(process.getInputStream()); - IOUtils.closeQuietly(process.getInputStream()); - IOUtils.closeQuietly(process.getOutputStream()); - IOUtils.closeQuietly(process.getErrorStream()); + Utils.closeQuietly(process.getInputStream()); + Utils.closeQuietly(process.getInputStream()); + Utils.closeQuietly(process.getOutputStream()); + Utils.closeQuietly(process.getErrorStream()); } } @@ -167,9 +165,8 @@ class CommandExecutor { @Override public void run() { - InputStreamReader isr = new InputStreamReader(is); - BufferedReader br = new BufferedReader(isr); - try { + try (InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr)) { String line; while ((line = br.readLine()) != null) { consumeLine(line); @@ -177,9 +174,6 @@ class CommandExecutor { } catch (IOException ioe) { exception = ioe; - } finally { - IOUtils.closeQuietly(br); - IOUtils.closeQuietly(isr); } } diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/api/Dirs.java b/sonar-runner-api/src/main/java/org/sonar/runner/api/Dirs.java index 1e9654e..369a745 100644 --- a/sonar-runner-api/src/main/java/org/sonar/runner/api/Dirs.java +++ b/sonar-runner-api/src/main/java/org/sonar/runner/api/Dirs.java @@ -19,7 +19,6 @@ */ package org.sonar.runner.api; -import org.apache.commons.io.FileUtils; import org.sonar.runner.impl.Logs; import java.io.File; @@ -54,7 +53,7 @@ class Dirs { workDir = new File(projectDir, path); } } - FileUtils.deleteQuietly(workDir); + Utils.deleteQuietly(workDir); runner.setProperty(RunnerProperties.WORK_DIR, workDir.getAbsolutePath()); Logs.info("Work directory: " + workDir.getAbsolutePath()); } diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/api/ForkedRunner.java b/sonar-runner-api/src/main/java/org/sonar/runner/api/ForkedRunner.java index 02ae333..fd7dc0b 100644 --- a/sonar-runner-api/src/main/java/org/sonar/runner/api/ForkedRunner.java +++ b/sonar-runner-api/src/main/java/org/sonar/runner/api/ForkedRunner.java @@ -19,8 +19,6 @@ */ package org.sonar.runner.api; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import org.sonar.runner.impl.BatchLauncherMain; import org.sonar.runner.impl.JarExtractor; @@ -163,24 +161,20 @@ public class ForkedRunner extends Runner { } private File writeProperties() { - OutputStream output = null; try { File file = File.createTempFile("sonar-project", ".properties"); - output = new FileOutputStream(file); - properties().store(output, "Generated by sonar-runner"); - return file; - + try (OutputStream output = new FileOutputStream(file)) { + properties().store(output, "Generated by sonar-runner"); + return file; + } } catch (Exception e) { throw new IllegalStateException("Fail to export sonar-runner properties", e); - - } finally { - IOUtils.closeQuietly(output); } } private void deleteTempFiles(ForkCommand forkCommand) { - FileUtils.deleteQuietly(forkCommand.jarFile); - FileUtils.deleteQuietly(forkCommand.propertiesFile); + Utils.deleteQuietly(forkCommand.jarFile); + Utils.deleteQuietly(forkCommand.propertiesFile); } private void fork(ForkCommand forkCommand) { diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/api/Runner.java b/sonar-runner-api/src/main/java/org/sonar/runner/api/Runner.java index c4013f6..b4e06bc 100644 --- a/sonar-runner-api/src/main/java/org/sonar/runner/api/Runner.java +++ b/sonar-runner-api/src/main/java/org/sonar/runner/api/Runner.java @@ -19,7 +19,6 @@ */ package org.sonar.runner.api; -import org.apache.commons.io.IOUtils; import org.sonar.runner.impl.InternalProperties; import javax.annotation.Nullable; @@ -102,14 +101,10 @@ public abstract class Runner { } private void writeProperties(File outputFile) { - OutputStream output = null; - try { - output = new FileOutputStream(outputFile); + try (OutputStream output = new FileOutputStream(outputFile)) { properties().store(output, "Generated by sonar-runner"); } catch (Exception e) { throw new IllegalStateException("Fail to export sonar-runner properties", e); - } finally { - IOUtils.closeQuietly(output); } } diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java b/sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java index d5e8d58..a4286c1 100644 --- a/sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java +++ b/sonar-runner-api/src/main/java/org/sonar/runner/api/Utils.java @@ -19,9 +19,19 @@ */ package org.sonar.runner.api; +import javax.annotation.Nullable; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; import java.util.Arrays; import java.util.Iterator; import java.util.Properties; +import java.nio.file.attribute.*; class Utils { private Utils() { @@ -33,7 +43,7 @@ class Utils { */ static String join(String[] array, String delimiter) { StringBuilder sb = new StringBuilder(); - Iterator it = Arrays.asList(array).iterator(); + Iterator it = Arrays.asList(array).iterator(); while (it.hasNext()) { sb.append(it.next()); if (!it.hasNext()) { @@ -48,4 +58,49 @@ class Utils { Object task = props.get(RunnerProperties.TASK); return task == null || ScanProperties.SCAN_TASK.equals(task); } + + public static void deleteQuietly(File f) { + try { + Files.walkFileTree(f.toPath(), new DeleteFileVisitor()); + } catch (IOException e) { + // ignore + } + } + + private static class DeleteFileVisitor extends SimpleFileVisitor { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (exc == null) { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } else { + // directory iteration failed; propagate exception + throw exc; + } + } + } + + public static void closeQuietly(@Nullable Closeable c) { + if (c == null) { + return; + } + + try { + c.close(); + } catch (IOException e) { + // ignore + } + } } diff --git a/sonar-runner-api/src/test/java/org/sonar/runner/api/CommandExecutorTest.java b/sonar-runner-api/src/test/java/org/sonar/runner/api/CommandExecutorTest.java index 88353ce..c585acf 100644 --- a/sonar-runner-api/src/test/java/org/sonar/runner/api/CommandExecutorTest.java +++ b/sonar-runner-api/src/test/java/org/sonar/runner/api/CommandExecutorTest.java @@ -19,7 +19,6 @@ */ package org.sonar.runner.api; -import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -29,6 +28,7 @@ import org.junit.rules.TestName; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import static org.fest.assertions.Assertions.assertThat; import static org.junit.Assert.fail; @@ -122,7 +122,7 @@ public class CommandExecutorTest { assertThat(exitCode).isEqualTo(0); File logFile = new File(workDir, "echo.log"); assertThat(logFile).exists(); - String log = FileUtils.readFileToString(logFile); + String log = new String(Files.readAllBytes(logFile.toPath())); assertThat(log).contains(workDir.getAbsolutePath()); assertThat(log).contains("Parameter: 1"); assertThat(log).contains("Environment variable: 2"); diff --git a/sonar-runner-api/src/test/java/org/sonar/runner/api/DirsTest.java b/sonar-runner-api/src/test/java/org/sonar/runner/api/DirsTest.java index a08d169..8313760 100644 --- a/sonar-runner-api/src/test/java/org/sonar/runner/api/DirsTest.java +++ b/sonar-runner-api/src/test/java/org/sonar/runner/api/DirsTest.java @@ -19,7 +19,6 @@ */ package org.sonar.runner.api; -import org.apache.commons.io.FilenameUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -54,7 +53,8 @@ public class DirsTest { File workDir = new File(runner.property("sonar.working.directory", null)); assertThat(workDir).isNotNull(); - assertThat(FilenameUtils.separatorsToUnix(workDir.getCanonicalPath())).contains("generated/reports"); + //separators from windows to unix + assertThat(workDir.getCanonicalPath().replace("\\", "/")).contains("generated/reports"); } @Test diff --git a/sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java b/sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java index 451ad3d..a56030d 100644 --- a/sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java +++ b/sonar-runner-api/src/test/java/org/sonar/runner/api/UtilsTest.java @@ -21,16 +21,24 @@ package org.sonar.runner.api; import org.junit.Test; +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Properties; +import static org.mockito.Mockito.verify; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doThrow; import static org.fest.assertions.Assertions.assertThat; public class UtilsTest { @Test public void should_join_strings() { - assertThat(Utils.join(new String[]{}, ",")).isEqualTo(""); - assertThat(Utils.join(new String[]{"foo"}, ",")).isEqualTo("foo"); - assertThat(Utils.join(new String[]{"foo", "bar"}, ",")).isEqualTo("foo,bar"); + assertThat(Utils.join(new String[] {}, ",")).isEqualTo(""); + assertThat(Utils.join(new String[] {"foo"}, ",")).isEqualTo("foo"); + assertThat(Utils.join(new String[] {"foo", "bar"}, ",")).isEqualTo("foo,bar"); } @Test @@ -48,4 +56,44 @@ public class UtilsTest { props.setProperty("sonar.task", "views"); assertThat(Utils.taskRequiresProject(props)).isFalse(); } + + @Test + public void close_quietly() throws IOException { + Closeable c = mock(Closeable.class); + doThrow(IOException.class).when(c).close(); + Utils.closeQuietly(c); + verify(c).close(); + } + + @Test + public void close_quietly_null() throws IOException { + Utils.closeQuietly(null); + } + + @Test + public void delete_non_empty_directory() throws IOException { + /*- + * Create test structure: + * tmp + * |-folder1 + * |- file1 + * |- folder2 + * |- file2 + */ + Path tmpDir = Files.createTempDirectory("junit"); + Path folder1 = tmpDir.resolve("folder1"); + Files.createDirectories(folder1); + Path file1 = folder1.resolve("file1"); + Files.write(file1, "test1".getBytes()); + + Path folder2 = folder1.resolve("folder2"); + Files.createDirectories(folder2); + Path file2 = folder1.resolve("file2"); + Files.write(file2, "test2".getBytes()); + + // delete it + assertThat(tmpDir.toFile()).exists(); + Utils.deleteQuietly(tmpDir.toFile()); + assertThat(tmpDir.toFile()).doesNotExist(); + } } diff --git a/sonar-runner-batch/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java b/sonar-runner-batch/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java index b845654..8298d63 100644 --- a/sonar-runner-batch/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java +++ b/sonar-runner-batch/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java @@ -23,11 +23,13 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import com.google.common.annotations.VisibleForTesting; + +import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Properties; -import org.apache.commons.io.IOUtils; + import org.slf4j.LoggerFactory; import org.sonar.api.utils.SonarException; import org.sonar.batch.bootstrapper.Batch; @@ -62,18 +64,15 @@ public class IsolatedLauncher { JoranConfigurator jc = new JoranConfigurator(); jc.setContext(context); context.reset(); - 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)); - try { + 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); - - } finally { - IOUtils.closeQuietly(input); + } catch (IOException e1) { + throw new SonarException("couldn't close resource", e1); } } diff --git a/sonar-runner-dist/pom.xml b/sonar-runner-dist/pom.xml index 0066ac9..229643b 100644 --- a/sonar-runner-dist/pom.xml +++ b/sonar-runner-dist/pom.xml @@ -52,6 +52,9 @@ org.apache.maven.plugins maven-jar-plugin + + org/sonar/runner/commonsio/* + false @@ -113,7 +116,7 @@ 279000 - 300000 + 350000 ${project.build.directory}/sonar-runner-${project.version}.zip diff --git a/sonar-runner-impl/pom.xml b/sonar-runner-impl/pom.xml index a8f725f..6d48d0c 100644 --- a/sonar-runner-impl/pom.xml +++ b/sonar-runner-impl/pom.xml @@ -23,6 +23,10 @@ org.codehaus.sonar sonar-home + + commons-io + commons-io + ${project.groupId} sonar-runner-batch diff --git a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncher.java b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncher.java index f19e43f..eebb592 100644 --- a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncher.java +++ b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncher.java @@ -19,6 +19,10 @@ */ package org.sonar.runner.impl; +import org.sonar.home.cache.PersistentCacheBuilder; + +import org.sonar.home.cache.PersistentCache; + import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -44,11 +48,21 @@ public class BatchLauncher { } public void execute(Properties props, List extensions) { - ServerConnection serverConnection = ServerConnection.create(props); + ServerConnection serverConnection = ServerConnection.create(props, getCache(props)); JarDownloader jarDownloader = new JarDownloader(serverConnection); doExecute(jarDownloader, props, extensions); } + private static PersistentCache getCache(Properties props) { + PersistentCacheBuilder builder = new PersistentCacheBuilder(); + + if ("true".equals(props.getProperty("sonar.forceUpdate"))) { + builder.forceUpdate(true); + } + + return builder.build(); + } + private static String[][] getMaskRules(final Properties props) { String maskRulesProp = props.getProperty(InternalProperties.RUNNER_MASK_RULES, null); String[] maskRulesConcat = maskRulesProp != null ? maskRulesProp.split(",") : new String[0]; diff --git a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncherMain.java b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncherMain.java index 3ec1c7b..ab70776 100644 --- a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncherMain.java +++ b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/BatchLauncherMain.java @@ -19,8 +19,6 @@ */ package org.sonar.runner.impl; -import org.apache.commons.io.IOUtils; - import java.io.FileInputStream; import java.io.IOException; import java.util.Collections; @@ -43,15 +41,12 @@ public class BatchLauncherMain { private Properties loadProperties(String arg) throws IOException { Properties props = new Properties(); - FileInputStream input = new FileInputStream(arg); - try { + try (FileInputStream input = new FileInputStream(arg)) { props.load(input); // just to be clean, do not forward properties that do not make sense in fork mode props.remove(InternalProperties.RUNNER_MASK_RULES); - - } finally { - IOUtils.closeQuietly(input); } + return props; } diff --git a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/Jars.java b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/Jars.java index 3593e94..5e4342e 100644 --- a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/Jars.java +++ b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/Jars.java @@ -19,13 +19,14 @@ */ package org.sonar.runner.impl; +import org.sonar.home.cache.FileCache; +import org.sonar.home.cache.FileCacheBuilder; +import org.sonar.home.log.StandardLog; + import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.sonar.home.cache.FileCache; -import org.sonar.home.cache.FileCacheBuilder; -import org.sonar.home.log.StandardLog; class Jars { private static final String BOOTSTRAP_INDEX_PATH = "/batch_bootstrap/index"; @@ -62,7 +63,7 @@ class Jars { try { List files = new ArrayList(); Logs.debug("Get bootstrap index..."); - String libs = connection.downloadString(BOOTSTRAP_INDEX_PATH); + String libs = connection.downloadStringCache(BOOTSTRAP_INDEX_PATH); Logs.debug("Get bootstrap completed"); String[] lines = libs.split("[\r\n]+"); BatchFileDownloader batchFileDownloader = new BatchFileDownloader(connection); diff --git a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/ServerConnection.java b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/ServerConnection.java index b68e480..c5b67e3 100644 --- a/sonar-runner-impl/src/main/java/org/sonar/runner/impl/ServerConnection.java +++ b/sonar-runner-impl/src/main/java/org/sonar/runner/impl/ServerConnection.java @@ -19,6 +19,7 @@ */ package org.sonar.runner.impl; +import org.sonar.home.cache.PersistentCache; import com.github.kevinsawicki.http.HttpRequest; import org.apache.commons.io.FileUtils; @@ -29,6 +30,7 @@ import java.net.URL; import java.net.UnknownHostException; import java.text.MessageFormat; import java.util.Properties; +import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,9 +45,14 @@ class ServerConnection { private final String serverUrl; private final String userAgent; - private ServerConnection(String serverUrl, String app, String appVersion) { + private final PersistentCache wsCache; + private final boolean isModePreview; + + private ServerConnection(String serverUrl, String app, String appVersion, boolean preview, PersistentCache cache) { this.serverUrl = removeEndSlash(serverUrl); this.userAgent = app + "/" + appVersion; + this.wsCache = cache; + this.isModePreview = preview; } private String removeEndSlash(String url) { @@ -55,11 +62,42 @@ class ServerConnection { return url.endsWith("/") ? url.substring(0, url.length() - 1) : url; } - static ServerConnection create(Properties properties) { + static ServerConnection create(Properties properties, PersistentCache cache) { String serverUrl = properties.getProperty("sonar.host.url"); String app = properties.getProperty(InternalProperties.RUNNER_APP); String appVersion = properties.getProperty(InternalProperties.RUNNER_APP_VERSION); - return new ServerConnection(serverUrl, app, appVersion); + String analysisMode = properties.getProperty("sonar.analysis.mode"); + boolean preview = "preview".equalsIgnoreCase(analysisMode); + + return new ServerConnection(serverUrl, app, appVersion, preview, cache); + } + + private class StringDownloader implements Callable { + private String url; + + StringDownloader(String url) { + this.url = url; + } + + @Override + public String call() throws Exception { + HttpRequest httpRequest = null; + try { + httpRequest = newHttpRequest(new URL(url)); + String charset = getCharsetFromContentType(httpRequest.contentType()); + if (charset == null || "".equals(charset)) { + charset = "UTF-8"; + } + if (!httpRequest.ok()) { + throw new IOException(MessageFormat.format(STATUS_RETURNED_BY_URL_IS_INVALID, url, httpRequest.code())); + } + return httpRequest.body(charset); + } finally { + if (httpRequest != null) { + httpRequest.disconnect(); + } + } + } } void download(String path, File toFile) { @@ -78,31 +116,22 @@ class ServerConnection { } FileUtils.deleteQuietly(toFile); throw new IllegalStateException("Fail to download: " + fullUrl, e); - } } - String downloadString(String path) throws IOException { + String downloadStringCache(String path) throws Exception { String fullUrl = serverUrl + path; - HttpRequest httpRequest = newHttpRequest(new URL(fullUrl)); try { - String charset = getCharsetFromContentType(httpRequest.contentType()); - if (charset == null || "".equals(charset)) { - charset = "UTF-8"; + if (isModePreview) { + return wsCache.getString(serverUrl, new StringDownloader(fullUrl)); + } else { + return new StringDownloader(fullUrl).call(); } - if (!httpRequest.ok()) { - throw new IOException(MessageFormat.format(STATUS_RETURNED_BY_URL_IS_INVALID, fullUrl, httpRequest.code())); - } - return httpRequest.body(charset); - } catch (HttpRequest.HttpRequestException e) { if (e.getCause() instanceof ConnectException || e.getCause() instanceof UnknownHostException) { Logs.error(MessageFormat.format(SONAR_SERVER_CAN_NOT_BE_REACHED, serverUrl)); } throw e; - - } finally { - httpRequest.disconnect(); } } diff --git a/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarDownloaderTest.java b/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarDownloaderTest.java index 487c579..aff8805 100644 --- a/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarDownloaderTest.java +++ b/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarDownloaderTest.java @@ -38,7 +38,7 @@ public class JarDownloaderTest { @Test public void should_download_jar_files() { - doReturn(new ArrayList()).when(downloader).download(); + doReturn(new ArrayList()).when(downloader).download(); List jarFiles = downloader.download(); assertThat(jarFiles).isNotNull(); } diff --git a/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarsTest.java b/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarsTest.java index cf685f8..b6fead1 100644 --- a/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarsTest.java +++ b/sonar-runner-impl/src/test/java/org/sonar/runner/impl/JarsTest.java @@ -51,7 +51,7 @@ public class JarsTest { File batchJar = temp.newFile("sonar-runner-batch.jar"); when(jarExtractor.extractToTemp("sonar-runner-batch")).thenReturn(batchJar); // index of the files to download - when(connection.downloadString("/batch_bootstrap/index")).thenReturn( + when(connection.downloadStringCache("/batch_bootstrap/index")).thenReturn( "cpd.jar|CA124VADFSDS\n" + "squid.jar|34535FSFSDF\n" ); @@ -60,7 +60,7 @@ public class JarsTest { List files = jars35.download(); assertThat(files).isNotNull(); - verify(connection, times(1)).downloadString("/batch_bootstrap/index"); + verify(connection, times(1)).downloadStringCache("/batch_bootstrap/index"); verifyNoMoreInteractions(connection); verify(fileCache, times(1)).get(eq("cpd.jar"), eq("CA124VADFSDS"), any(FileCache.Downloader.class)); verify(fileCache, times(1)).get(eq("squid.jar"), eq("34535FSFSDF"), any(FileCache.Downloader.class)); @@ -72,7 +72,7 @@ public class JarsTest { File batchJar = temp.newFile("sonar-runner-batch.jar"); when(jarExtractor.extractToTemp("sonar-runner-batch")).thenReturn(batchJar); // index of the files to download - when(connection.downloadString("/batch_bootstrap/index")).thenThrow(new IllegalStateException()); + when(connection.downloadStringCache("/batch_bootstrap/index")).thenThrow(new IllegalStateException()); Jars jars35 = new Jars(fileCache, connection, jarExtractor); try { diff --git a/sonar-runner-impl/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java b/sonar-runner-impl/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java index bb671bf..c8bf525 100644 --- a/sonar-runner-impl/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java +++ b/sonar-runner-impl/src/test/java/org/sonar/runner/impl/ServerConnectionTest.java @@ -19,12 +19,17 @@ */ package org.sonar.runner.impl; +import org.junit.Before; +import org.sonar.home.cache.PersistentCacheBuilder; +import org.sonar.home.cache.PersistentCache; import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; import java.util.Properties; import static org.fest.assertions.Assertions.assertThat; @@ -38,14 +43,21 @@ public class ServerConnectionTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); + private PersistentCache cache = null; + + @Before + public void setUp() { + cache = new PersistentCacheBuilder().setSonarHome(temp.getRoot().toPath()).build(); + } + @Test public void should_download_to_string() throws Exception { httpServer.setMockResponseData("abcde"); Properties props = new Properties(); props.setProperty("sonar.host.url", httpServer.url()); - ServerConnection connection = ServerConnection.create(props); - String response = connection.downloadString("/batch/index.txt"); + ServerConnection connection = ServerConnection.create(props, cache); + String response = connection.downloadStringCache("/batch/index.txt"); assertThat(response).isEqualTo("abcde"); } @@ -56,12 +68,51 @@ public class ServerConnectionTest { Properties props = new Properties(); props.setProperty("sonar.host.url", httpServer.url()); - ServerConnection connection = ServerConnection.create(props); + ServerConnection connection = ServerConnection.create(props, cache); File toFile = temp.newFile(); connection.download("/batch/index.txt", toFile); assertThat(FileUtils.readFileToString(toFile)).isEqualTo("abcde"); } + + @Test + public void should_cache_jar_list() throws Exception { + File cacheDir = new File(temp.getRoot(), "ws_cache"); + httpServer.setMockResponseData("abcde"); + Properties props = new Properties(); + props.setProperty("sonar.host.url", httpServer.url() + "/"); + props.setProperty("sonar.analysis.mode", "preview"); + + assertThat(cacheDir.list().length).isEqualTo(0); + ServerConnection connection = ServerConnection.create(props, cache); + String str = connection.downloadStringCache("/batch/index.txt"); + + assertThat(str).isEqualTo("abcde"); + assertThat(cacheDir.list().length).isEqualTo(2); + + httpServer.setMockResponseData("never requested"); + str = connection.downloadStringCache("/batch/index.txt"); + assertThat(str).isEqualTo("abcde"); + } + + @Test + public void should_not_cache_not_preview() throws Exception { + File cacheDir = new File(temp.getRoot(), "ws_cache"); + httpServer.setMockResponseData("abcde"); + Properties props = new Properties(); + props.setProperty("sonar.host.url", httpServer.url() + "/"); + + assertThat(cacheDir.list().length).isEqualTo(0); + ServerConnection connection = ServerConnection.create(props, cache); + String str = connection.downloadStringCache("/batch/index.txt"); + + assertThat(str).isEqualTo("abcde"); + assertThat(cacheDir.list().length).isEqualTo(0); + + httpServer.setMockResponseData("request2"); + str = connection.downloadStringCache("/batch/index.txt"); + assertThat(str).isEqualTo("request2"); + } // SONARPLUGINS-3061 @Test @@ -70,7 +121,7 @@ public class ServerConnectionTest { Properties props = new Properties(); props.setProperty("sonar.host.url", httpServer.url() + "/"); - ServerConnection connection = ServerConnection.create(props); + ServerConnection connection = ServerConnection.create(props, cache); File toFile = temp.newFile(); connection.download("/batch/index.txt", toFile); @@ -82,7 +133,7 @@ public class ServerConnectionTest { Properties props = new Properties(); props.setProperty("sonar.host.url", "http://localhost:" + NetworkUtil.getNextAvailablePort()); - ServerConnection connection = ServerConnection.create(props); + ServerConnection connection = ServerConnection.create(props, cache); File toFile = temp.newFile(); try { connection.download("/batch/index.txt", toFile); @@ -97,9 +148,9 @@ public class ServerConnectionTest { Properties props = new Properties(); props.setProperty("sonar.host.url", "http://localhost:" + NetworkUtil.getNextAvailablePort()); - ServerConnection connection = ServerConnection.create(props); + ServerConnection connection = ServerConnection.create(props, cache); try { - connection.downloadString("/batch/index.txt"); + connection.downloadStringCache("/batch/index.txt"); fail(); } catch (Exception e) { // success -- 2.39.5