@@ -60,12 +60,6 @@ | |||
</properties> | |||
<dependencies> | |||
<!-- Would be embedded in final JAR --> | |||
<dependency> | |||
<groupId>org.codehaus.sonar</groupId> | |||
<artifactId>sonar-batch-bootstrapper</artifactId> | |||
<version>${sonar.buildVersion}</version> | |||
</dependency> | |||
<!-- Would be available after bootstrapping --> | |||
<dependency> | |||
<groupId>ch.qos.logback</groupId> |
@@ -22,7 +22,7 @@ else | |||
fi | |||
JAVA_CMD="`which java`" | |||
JAVA_CLASSPATH="${SONAR_RUNNER_HOME}"/lib/sonar-runner.jar:"${SONAR_RUNNER_HOME}"/lib/sonar-batch-bootstrapper.jar | |||
JAVA_CLASSPATH="${SONAR_RUNNER_HOME}"/lib/sonar-runner.jar | |||
PROJECT_HOME=`pwd` | |||
#echo "Info: Using sonar-runner at $SONAR_RUNNER_HOME" |
@@ -70,7 +70,7 @@ echo %SONAR_RUNNER_HOME% | |||
set PROJECT_HOME=%CD% | |||
%JAVA_EXEC% %SONAR_RUNNER_OPTS% -classpath "%SONAR_RUNNER_HOME%\lib\sonar-runner.jar";"%SONAR_RUNNER_HOME%\lib\sonar-batch-bootstrapper.jar" "-Drunner.home=%SONAR_RUNNER_HOME%" "-Dproject.home=%PROJECT_HOME%" org.sonar.runner.Main %* | |||
%JAVA_EXEC% %SONAR_RUNNER_OPTS% -classpath "%SONAR_RUNNER_HOME%\lib\sonar-runner.jar" "-Drunner.home=%SONAR_RUNNER_HOME%" "-Dproject.home=%PROJECT_HOME%" org.sonar.runner.Main %* | |||
@@ -23,6 +23,7 @@ package org.sonar.runner; | |||
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 org.apache.commons.configuration.CompositeConfiguration; | |||
import org.apache.commons.configuration.Configuration; | |||
import org.apache.commons.configuration.EnvironmentConfiguration; | |||
@@ -37,29 +38,28 @@ import org.sonar.batch.Batch; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.runner.model.SonarProjectBuilder; | |||
import java.io.File; | |||
import java.io.InputStream; | |||
import java.util.Properties; | |||
/** | |||
* Contrary to {@link org.sonar.runner.Runner}, this class is executed within the classloader | |||
* provided by the server. It contains the installed plugins and the same version of sonar-batch as the server. | |||
* | |||
* TODO : instead of depending on Runner, that is not in the same classloader, we could simply use Properties : | |||
* sonar.runner.version, sonar.runner.debug, sonar.runner.projectDir, sonar.runner.workDir and all the | |||
* other properties. | |||
*/ | |||
public class Launcher { | |||
private Runner runner; | |||
private Properties propertiesFromRunner; | |||
public Launcher(Runner runner) { | |||
this.runner = runner; | |||
public Launcher(Properties properties) { | |||
this.propertiesFromRunner = properties; | |||
} | |||
/** | |||
* This method invoked from {@link Main}. Do not rename it. | |||
*/ | |||
public void execute() { | |||
ProjectDefinition project = SonarProjectBuilder.create(runner.getProjectDir(), runner.getProperties()).generateProjectDefinition(); | |||
File baseDir = new File(propertiesFromRunner.getProperty(Runner.PROPERTY_PROJECT_DIR)); | |||
ProjectDefinition project = SonarProjectBuilder.create(baseDir, propertiesFromRunner).generateProjectDefinition(); | |||
Configuration initialConfiguration = getInitialConfiguration(project); | |||
initLogging(initialConfiguration); | |||
executeBatch(project, initialConfiguration); | |||
@@ -67,7 +67,8 @@ public class Launcher { | |||
private void executeBatch(ProjectDefinition project, Configuration initialConfiguration) { | |||
ProjectReactor reactor = new ProjectReactor(project); | |||
Batch batch = Batch.create(reactor, initialConfiguration, new EnvironmentInformation("Runner", runner.getRunnerVersion())); | |||
String runnerVersion = propertiesFromRunner.getProperty(Runner.PROPERTY_RUNNER_VERSION); | |||
Batch batch = Batch.create(reactor, initialConfiguration, new EnvironmentInformation("Runner", runnerVersion)); | |||
batch.execute(); | |||
} | |||
@@ -77,7 +78,7 @@ public class Launcher { | |||
jc.setContext(context); | |||
context.reset(); | |||
InputStream input = Batch.class.getResourceAsStream("/org/sonar/batch/logback.xml"); | |||
System.setProperty("ROOT_LOGGER_LEVEL", runner.isDebug() ? "DEBUG" : "INFO"); | |||
System.setProperty("ROOT_LOGGER_LEVEL", isDebug() ? "DEBUG" : "INFO"); | |||
context.putProperty("SQL_LOGGER_LEVEL", getSqlLevel(initialConfiguration));// since 2.14. Ignored on previous versions. | |||
context.putProperty("SQL_RESULTS_LOGGER_LEVEL", getSqlResultsLevel(initialConfiguration));// since 2.14. Ignored on previous versions. | |||
try { | |||
@@ -91,11 +92,18 @@ public class Launcher { | |||
} | |||
} | |||
@VisibleForTesting | |||
protected boolean isDebug() { | |||
return Boolean.parseBoolean(propertiesFromRunner.getProperty(Runner.PROPERTY_VERBOSE, propertiesFromRunner.getProperty(Runner.PROPERTY_OLD_DEBUG_MODE, "false"))); | |||
} | |||
@VisibleForTesting | |||
protected static String getSqlLevel(Configuration config) { | |||
boolean showSql = config.getBoolean("sonar.showSql", false); | |||
return showSql ? "DEBUG" : "WARN"; | |||
} | |||
@VisibleForTesting | |||
protected static String getSqlResultsLevel(Configuration config) { | |||
boolean showSql = config.getBoolean("sonar.showSqlResults", false); | |||
return showSql ? "DEBUG" : "WARN"; |
@@ -20,8 +20,8 @@ | |||
package org.sonar.runner; | |||
import org.sonar.batch.bootstrapper.BootstrapException; | |||
import org.sonar.batch.bootstrapper.BootstrapperIOUtils; | |||
import org.sonar.runner.bootstrapper.BootstrapException; | |||
import org.sonar.runner.bootstrapper.BootstrapperIOUtils; | |||
import java.io.File; | |||
import java.io.FileInputStream; |
@@ -19,10 +19,10 @@ | |||
*/ | |||
package org.sonar.runner; | |||
import org.sonar.batch.bootstrapper.BootstrapClassLoader; | |||
import org.sonar.batch.bootstrapper.BootstrapException; | |||
import org.sonar.batch.bootstrapper.Bootstrapper; | |||
import org.sonar.batch.bootstrapper.BootstrapperIOUtils; | |||
import org.sonar.runner.bootstrapper.BootstrapClassLoader; | |||
import org.sonar.runner.bootstrapper.BootstrapException; | |||
import org.sonar.runner.bootstrapper.Bootstrapper; | |||
import org.sonar.runner.bootstrapper.BootstrapperIOUtils; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -37,11 +37,15 @@ import java.util.Properties; | |||
* @since 1.1 | |||
*/ | |||
public final class Runner { | |||
public static final String PROPERTY_PROJECT_DIR = "sonar.runner.projectDir"; | |||
public static final String PROPERTY_RUNNER_VERSION = "sonar.runner.version"; | |||
/** | |||
* @deprecated Replaced by sonar.verbose since 1.2 | |||
*/ | |||
@Deprecated | |||
public static final String DEBUG_MODE = "runner.debug"; | |||
public static final String PROPERTY_OLD_DEBUG_MODE = "runner.debug"; | |||
/** | |||
* @since 1.2 | |||
@@ -109,6 +113,8 @@ public final class Runner { | |||
if (!projectDir.isDirectory() || !projectDir.exists()) { | |||
throw new IllegalArgumentException("Project home must be an existing directory: " + path); | |||
} | |||
// project home exist, add its absolute path as "sonar.runner.projectDir" property | |||
properties.put(PROPERTY_PROJECT_DIR, projectDir.getAbsolutePath()); | |||
workDir = initWorkDir(); | |||
} | |||
@@ -145,10 +151,6 @@ public final class Runner { | |||
return properties; | |||
} | |||
public boolean isDebug() { | |||
return Boolean.parseBoolean(properties.getProperty(PROPERTY_VERBOSE, properties.getProperty(DEBUG_MODE, "false"))); | |||
} | |||
public String getRunnerVersion() { | |||
InputStream in = null; | |||
try { | |||
@@ -201,12 +203,8 @@ public final class Runner { | |||
try { | |||
Thread.currentThread().setContextClassLoader(sonarClassLoader); | |||
Class<?> launcherClass = sonarClassLoader.findClass("org.sonar.runner.Launcher"); | |||
// TODO: hack to instantiate SonarProjectBuilder in this classloader otherwise it will be found in the parent one, where no deps are | |||
// available | |||
sonarClassLoader.findClass("org.sonar.runner.model.SonarProjectBuilder"); | |||
// END of hack | |||
Constructor<?> constructor = launcherClass.getConstructor(Runner.class); | |||
Object launcher = constructor.newInstance(this); | |||
Constructor<?> constructor = launcherClass.getConstructor(Properties.class); | |||
Object launcher = constructor.newInstance(getProperties()); | |||
Method method = launcherClass.getMethod("execute"); | |||
method.invoke(launcher); | |||
} catch (InvocationTargetException e) { |
@@ -0,0 +1,121 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
import java.io.IOException; | |||
import java.net.URL; | |||
import java.net.URLClassLoader; | |||
import java.util.Enumeration; | |||
/** | |||
* Special {@link URLClassLoader} to execute Sonar, which restricts loading from parent. | |||
*/ | |||
public class BootstrapClassLoader extends URLClassLoader { | |||
private final String[] unmaskedPackages; | |||
public BootstrapClassLoader(ClassLoader parent, String... unmaskedPackages) { | |||
super(new URL[0], parent); | |||
this.unmaskedPackages = unmaskedPackages; | |||
} | |||
/** | |||
* {@inheritDoc} Visibility of a method has been relaxed to public. | |||
*/ | |||
@Override | |||
public void addURL(URL url) { | |||
super.addURL(url); | |||
} | |||
/** | |||
* {@inheritDoc} Visibility of a method has been relaxed to public. | |||
*/ | |||
@Override | |||
public Class<?> findClass(String name) throws ClassNotFoundException { | |||
return super.findClass(name); | |||
} | |||
/** | |||
* @return true, if class can be loaded from parent ClassLoader | |||
*/ | |||
boolean canLoadFromParent(String name) { | |||
for (String pkg : unmaskedPackages) { | |||
if (name.startsWith(pkg + ".")) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Same behavior as in {@link URLClassLoader#loadClass(String, boolean)}, except loading from parent. | |||
*/ | |||
@Override | |||
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { | |||
// First, check if the class has already been loaded | |||
Class<?> c = findLoadedClass(name); | |||
if (c == null) { | |||
try { | |||
// Load from parent | |||
if (getParent() != null && canLoadFromParent(name)) { | |||
c = getParent().loadClass(name); | |||
} else { | |||
// Load from system | |||
// I don't know for other vendors, but for Oracle JVM : | |||
// - ClassLoader.getSystemClassLoader() is sun.misc.Launcher$AppClassLoader. It contains app classpath. | |||
// - ClassLoader.getSystemClassLoader().getParent() is sun.misc.Launcher$ExtClassLoader. It contains core JVM | |||
ClassLoader systemClassLoader = getSystemClassLoader(); | |||
if (systemClassLoader.getParent() != null) { | |||
systemClassLoader = systemClassLoader.getParent(); | |||
} | |||
c = systemClassLoader.loadClass(name); | |||
} | |||
} catch (ClassNotFoundException e) { | |||
// If still not found, then invoke findClass in order | |||
// to find the class. | |||
c = findClass(name); | |||
} | |||
} | |||
if (resolve) { | |||
resolveClass(c); | |||
} | |||
return c; | |||
} | |||
/** | |||
* Unlike {@link URLClassLoader#getResource(String)} don't return resource from parent. | |||
* See http://jira.codehaus.org/browse/SONAR-2276 | |||
*/ | |||
@Override | |||
public URL getResource(String name) { | |||
return findResource(name); | |||
} | |||
/** | |||
* Unlike {@link URLClassLoader#getResources(String)} don't return resources from parent. | |||
* See http://jira.codehaus.org/browse/SONAR-2276 | |||
*/ | |||
@Override | |||
public Enumeration<URL> getResources(String name) throws IOException { | |||
return findResources(name); | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
public class BootstrapException extends RuntimeException { | |||
public BootstrapException(String message) { | |||
super(message); | |||
} | |||
public BootstrapException(Throwable cause) { | |||
super(cause); | |||
} | |||
public BootstrapException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} |
@@ -0,0 +1,167 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
import java.io.*; | |||
import java.net.HttpURLConnection; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
public class Bootstrapper { | |||
private static final String VERSION_PATH = "/api/server/version"; | |||
private static final String BATCH_PATH = "/batch/"; | |||
public static final int CONNECT_TIMEOUT_MILLISECONDS = 30000; | |||
public static final int READ_TIMEOUT_MILLISECONDS = 60000; | |||
private File bootDir; | |||
private String serverUrl; | |||
private String productToken; | |||
private String serverVersion; | |||
/** | |||
* @param productToken part of User-Agent request-header field - see http://tools.ietf.org/html/rfc1945#section-10.15 | |||
*/ | |||
public Bootstrapper(String productToken, String serverUrl, File workDir) { | |||
this.productToken = productToken; | |||
bootDir = new File(workDir, "batch"); | |||
bootDir.mkdirs(); | |||
if (serverUrl.endsWith("/")) { | |||
this.serverUrl = serverUrl.substring(0, serverUrl.length() - 1); | |||
} else { | |||
this.serverUrl = serverUrl; | |||
} | |||
} | |||
/** | |||
* @return server url | |||
*/ | |||
public String getServerUrl() { | |||
return serverUrl; | |||
} | |||
/** | |||
* @return server version | |||
*/ | |||
public String getServerVersion() { | |||
if (serverVersion == null) { | |||
try { | |||
serverVersion = remoteContent(VERSION_PATH); | |||
} catch (IOException e) { | |||
throw new BootstrapException(e.getMessage(), e); | |||
} | |||
} | |||
return serverVersion; | |||
} | |||
/** | |||
* Download batch files from server and creates {@link BootstrapClassLoader}. | |||
* To use this method version of Sonar should be at least 2.6. | |||
* | |||
* @param urls additional URLs for loading classes and resources | |||
* @param parent parent ClassLoader | |||
* @param unmaskedPackages only classes and resources from those packages would be available for loading from parent | |||
*/ | |||
public BootstrapClassLoader createClassLoader(URL[] urls, ClassLoader parent, String... unmaskedPackages) { | |||
BootstrapClassLoader classLoader = new BootstrapClassLoader(parent, unmaskedPackages); | |||
List<File> files = downloadBatchFiles(); | |||
for (URL url : urls) { | |||
classLoader.addURL(url); | |||
} | |||
for (File file : files) { | |||
try { | |||
classLoader.addURL(file.toURI().toURL()); | |||
} catch (MalformedURLException e) { | |||
throw new BootstrapException(e); | |||
} | |||
} | |||
return classLoader; | |||
} | |||
private void remoteContentToFile(String path, File toFile) { | |||
InputStream input = null; | |||
FileOutputStream output = null; | |||
String fullUrl = serverUrl + path; | |||
try { | |||
HttpURLConnection connection = newHttpConnection(new URL(fullUrl)); | |||
output = new FileOutputStream(toFile, false); | |||
input = connection.getInputStream(); | |||
BootstrapperIOUtils.copyLarge(input, output); | |||
} catch (IOException e) { | |||
BootstrapperIOUtils.closeQuietly(output); | |||
BootstrapperIOUtils.deleteFileQuietly(toFile); | |||
throw new BootstrapException("Fail to download the file: " + fullUrl, e); | |||
} finally { | |||
BootstrapperIOUtils.closeQuietly(input); | |||
BootstrapperIOUtils.closeQuietly(output); | |||
} | |||
} | |||
String remoteContent(String path) throws IOException { | |||
String fullUrl = serverUrl + path; | |||
HttpURLConnection conn = newHttpConnection(new URL(fullUrl)); | |||
Reader reader = new InputStreamReader((InputStream) conn.getContent()); | |||
try { | |||
int statusCode = conn.getResponseCode(); | |||
if (statusCode != HttpURLConnection.HTTP_OK) { | |||
throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode); | |||
} | |||
return BootstrapperIOUtils.toString(reader); | |||
} finally { | |||
BootstrapperIOUtils.closeQuietly(reader); | |||
conn.disconnect(); | |||
} | |||
} | |||
/** | |||
* By convention, the product tokens are listed in order of their significance for identifying the application. | |||
*/ | |||
String getUserAgent() { | |||
return "sonar-bootstrapper/" + BootstrapperVersion.getVersion() + " " + productToken; | |||
} | |||
HttpURLConnection newHttpConnection(URL url) throws IOException { | |||
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); | |||
connection.setConnectTimeout(CONNECT_TIMEOUT_MILLISECONDS); | |||
connection.setReadTimeout(READ_TIMEOUT_MILLISECONDS); | |||
connection.setInstanceFollowRedirects(true); | |||
connection.setRequestMethod("GET"); | |||
connection.setRequestProperty("User-Agent", getUserAgent()); | |||
return connection; | |||
} | |||
private List<File> downloadBatchFiles() { | |||
try { | |||
List<File> files = new ArrayList<File>(); | |||
String libs = remoteContent(BATCH_PATH); | |||
for (String lib : libs.split(",")) { | |||
File file = new File(bootDir, lib); | |||
remoteContentToFile(BATCH_PATH + lib, file); | |||
files.add(file); | |||
} | |||
return files; | |||
} catch (Exception e) { | |||
throw new BootstrapException(e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
import java.io.*; | |||
public final class BootstrapperIOUtils { | |||
private BootstrapperIOUtils() { | |||
// only static methods | |||
} | |||
/** | |||
* The default buffer size to use. | |||
*/ | |||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; | |||
/** | |||
* Unconditionally close a <code>Closeable</code>. | |||
*/ | |||
public static void closeQuietly(Closeable closeable) { | |||
try { | |||
if (closeable != null) { | |||
closeable.close(); | |||
} | |||
} catch (IOException ioe) { // NOSONAR | |||
} | |||
} | |||
/** | |||
* Get the contents of a <code>Reader</code> as a String. | |||
*/ | |||
public static String toString(Reader input) throws IOException { | |||
StringWriter sw = new StringWriter(); | |||
copyLarge(input, sw); | |||
return sw.toString(); | |||
} | |||
/** | |||
* Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>. | |||
*/ | |||
public static long copyLarge(InputStream input, OutputStream output) throws IOException { | |||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; | |||
long count = 0; | |||
int n = 0; | |||
while (-1 != (n = input.read(buffer))) { | |||
output.write(buffer, 0, n); | |||
count += n; | |||
} | |||
return count; | |||
} | |||
/** | |||
* Copy chars from a <code>Reader</code> to a <code>Writer</code>. | |||
*/ | |||
public static long copyLarge(Reader input, Writer output) throws IOException { | |||
char[] buffer = new char[DEFAULT_BUFFER_SIZE]; | |||
long count = 0; | |||
int n = 0; | |||
while (-1 != (n = input.read(buffer))) { | |||
output.write(buffer, 0, n); | |||
count += n; | |||
} | |||
return count; | |||
} | |||
/** | |||
* Deletes a file (not a directory). | |||
*/ | |||
public static boolean deleteFileQuietly(File file) { | |||
if (file == null) { | |||
return false; | |||
} | |||
try { | |||
return file.delete(); | |||
} catch (Exception e) { | |||
return false; | |||
} | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.Properties; | |||
public enum BootstrapperVersion { | |||
INSTANCE; | |||
private static final String PROPERTIES_PATH = "/org/sonar/runner/version.txt"; | |||
private String version; | |||
public static String getVersion() { | |||
return INSTANCE.version; | |||
} | |||
private BootstrapperVersion() { | |||
InputStream input = getClass().getResourceAsStream(PROPERTIES_PATH); | |||
try { | |||
Properties properties = new Properties(); | |||
properties.load(input); | |||
this.version = properties.getProperty("version"); | |||
} catch (IOException e) { | |||
// Can not load the version | |||
this.version = ""; | |||
} finally { | |||
BootstrapperIOUtils.closeQuietly(input); | |||
} | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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 | |||
*/ | |||
/** | |||
* Provides API to bootstrap Sonar Batch. | |||
*/ | |||
package org.sonar.runner.bootstrapper; |
@@ -23,6 +23,8 @@ import org.apache.commons.configuration.BaseConfiguration; | |||
import org.apache.commons.configuration.Configuration; | |||
import org.junit.Test; | |||
import java.util.Properties; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class LauncherTest { | |||
@@ -53,4 +55,21 @@ public class LauncherTest { | |||
assertThat(Launcher.getSqlResultsLevel(conf)).isEqualTo("WARN"); | |||
} | |||
@Test | |||
public void shouldDetermineVerboseMode() { | |||
Properties properties = new Properties(); | |||
Launcher launcher = new Launcher(properties); | |||
assertThat(launcher.isDebug()).isFalse(); | |||
properties.setProperty(Runner.PROPERTY_VERBOSE, "true"); | |||
assertThat(launcher.isDebug()).isTrue(); | |||
} | |||
@Test | |||
public void shouldSupportDeprecatedDebugProperty() { | |||
Properties properties = new Properties(); | |||
Launcher launcher = new Launcher(properties); | |||
properties.setProperty(Runner.PROPERTY_OLD_DEBUG_MODE, "true"); | |||
assertThat(launcher.isDebug()).isTrue(); | |||
} | |||
} |
@@ -22,8 +22,8 @@ package org.sonar.runner; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.batch.bootstrapper.BootstrapException; | |||
import org.sonar.batch.bootstrapper.Bootstrapper; | |||
import org.sonar.runner.bootstrapper.BootstrapException; | |||
import org.sonar.runner.bootstrapper.Bootstrapper; | |||
import java.io.File; | |||
import java.util.Properties; | |||
@@ -95,23 +95,6 @@ public class RunnerTest { | |||
assertThat(runner.getServerURL()).isEqualTo("foo"); | |||
} | |||
@Test | |||
public void shouldDetermineVerboseMode() { | |||
Properties properties = new Properties(); | |||
Runner runner = Runner.create(properties); | |||
assertThat(runner.isDebug()).isFalse(); | |||
properties.setProperty(Runner.PROPERTY_VERBOSE, "true"); | |||
assertThat(runner.isDebug()).isTrue(); | |||
} | |||
@Test | |||
public void shouldSupportDeprecatedDebugProperty() { | |||
Properties properties = new Properties(); | |||
Runner runner = Runner.create(properties); | |||
properties.setProperty(Runner.DEBUG_MODE, "true"); | |||
assertThat(runner.isDebug()).isTrue(); | |||
} | |||
@Test | |||
public void shouldInitDirs() throws Exception { | |||
Properties props = new Properties(); |
@@ -0,0 +1,61 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.runner.bootstrapper.BootstrapClassLoader; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class BootstrapClassLoaderTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@Test | |||
public void shouldRestrictLoadingFromParent() throws Exception { | |||
BootstrapClassLoader classLoader = new BootstrapClassLoader(getClass().getClassLoader(), "org.sonar.ant"); | |||
assertThat(classLoader.canLoadFromParent("org.sonar.ant.Launcher")).isTrue(); | |||
assertThat(classLoader.canLoadFromParent("org.objectweb.asm.ClassVisitor")).isFalse(); | |||
} | |||
@Test | |||
public void use_isolated_system_classloader_when_parent_is_excluded() throws ClassNotFoundException { | |||
thrown.expect(ClassNotFoundException.class); | |||
thrown.expectMessage("org.junit.Test"); | |||
ClassLoader parent = getClass().getClassLoader(); | |||
BootstrapClassLoader classLoader = new BootstrapClassLoader(parent); | |||
// JUnit is available in the parent classloader (classpath used to execute this test) but not in the core JVM | |||
assertThat(classLoader.loadClass("java.lang.String", false)).isNotNull(); | |||
classLoader.loadClass("org.junit.Test", false); | |||
} | |||
@Test | |||
public void find_in_parent_when_matches_unmasked_packages() throws ClassNotFoundException { | |||
ClassLoader parent = getClass().getClassLoader(); | |||
BootstrapClassLoader classLoader = new BootstrapClassLoader(parent, "org.junit"); | |||
// JUnit is available in the parent classloader (classpath used to execute this test) but not in the core JVM | |||
assertThat(classLoader.loadClass("org.junit.Test", false)).isNotNull(); | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
import org.junit.Test; | |||
import org.sonar.runner.bootstrapper.Bootstrapper; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class BootstrapperTest { | |||
@Test | |||
public void shouldRemoveLastUrlSlash() { | |||
Bootstrapper bootstrapper = new Bootstrapper("", "http://test/", new File("target")); | |||
assertThat(bootstrapper.getServerUrl()).isEqualTo("http://test"); | |||
} | |||
@Test(expected = Exception.class) | |||
public void shouldFailIfCanNotConnectServer() { | |||
Bootstrapper bootstrapper = new Bootstrapper("", "http://unknown.foo", new File("target")); | |||
bootstrapper.getServerVersion(); | |||
} | |||
@Test | |||
public void shouldReturnUserAgent() { | |||
Bootstrapper bootstrapper = new Bootstrapper("test/0.1", "http://unknown.foo", new File("target")); | |||
String userAgent = bootstrapper.getUserAgent(); | |||
assertThat(userAgent.length()).isGreaterThan(0); | |||
assertThat(userAgent).startsWith("sonar-bootstrapper/"); | |||
assertThat(userAgent).endsWith(" test/0.1"); | |||
} | |||
@Test | |||
public void shouldReturnValidVersion() { | |||
Bootstrapper bootstrapper = new Bootstrapper("", "http://test", new File("target")) { | |||
@Override | |||
String remoteContent(String path) throws IOException { | |||
return "2.6"; | |||
} | |||
}; | |||
assertThat(bootstrapper.getServerVersion()).isEqualTo("2.6"); | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
/* | |||
* Sonar Standalone Runner | |||
* 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.bootstrapper; | |||
import org.junit.Test; | |||
import org.sonar.runner.bootstrapper.BootstrapperVersion; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class BootstrapperVersionTest { | |||
@Test | |||
public void shouldLoadVersion() { | |||
String version = BootstrapperVersion.getVersion(); | |||
assertThat(version).contains("."); | |||
assertThat(version).doesNotContain("$"); | |||
} | |||
} |