diff options
author | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-01-19 02:20:45 +0300 |
---|---|---|
committer | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-01-24 01:14:07 +0300 |
commit | 6b5035087075113699015583fd4d76b75bf36894 (patch) | |
tree | 97a3a3ef3be082d68db071405f7aab50d4963a19 | |
parent | a1fca497333231931a3df3e3973918ade12ab6bc (diff) | |
download | sonarqube-6b5035087075113699015583fd4d76b75bf36894.tar.gz sonarqube-6b5035087075113699015583fd4d76b75bf36894.zip |
SONAR-2106: New Java library to bootstrap project analysis
* Add BatchResourcesServlet to allow downloading libraries from server
* Create in memory POM for non-maven environments
* Provide fake MavenPluginExecutor for non-maven environments
* Add new module sonar-batch-maven-compat with shaded maven-project
22 files changed, 767 insertions, 316 deletions
@@ -14,6 +14,8 @@ <module>archetypes/sonar-basic-plugin</module> <module>archetypes/sonar-gwt-plugin</module> <module>sonar-batch</module> + <module>sonar-batch-bootstrapper</module> + <module>sonar-batch-maven-compat</module> <module>sonar-channel</module> <module>sonar-check-api</module> <module>sonar-colorizer</module> diff --git a/sonar-batch-bootstrapper/pom.xml b/sonar-batch-bootstrapper/pom.xml new file mode 100644 index 00000000000..75a7498f456 --- /dev/null +++ b/sonar-batch-bootstrapper/pom.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar</artifactId> + <version>2.6-SNAPSHOT</version> + </parent> + + <artifactId>sonar-batch-bootstrapper</artifactId> + <name>Sonar :: Batch Bootstrapper</name> + <description>Provides API to bootstrap Sonar Batch.</description> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-all</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BatchDownloader.java b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BatchDownloader.java new file mode 100644 index 00000000000..b5eba165324 --- /dev/null +++ b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BatchDownloader.java @@ -0,0 +1,134 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class BatchDownloader { + + 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 String serverUrl; + private String serverVersion; + + public BatchDownloader(String serverUrl) { + 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 RuntimeException(e.getMessage(), e); + } + } + return serverVersion; + } + + /** + * @return list of downloaded files + */ + public List<File> downloadBatchFiles(File toDir) { + try { + List<File> files = new ArrayList<File>(); + + String libs = remoteContent(BATCH_PATH); + + for (String lib : libs.split(",")) { + File file = new File(toDir, lib); + remoteContentToFile(BATCH_PATH + lib, file); + files.add(file); + } + + return files; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + 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 (Exception e) { + BootstrapperIOUtils.closeQuietly(output); + BootstrapperIOUtils.deleteFileQuietly(toFile); + throw new RuntimeException("Fail to download the file: " + fullUrl); + } 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(); + } + } + + static 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"); + // TODO connection.setRequestProperty("User-Agent", userAgent); + return connection; + } + +} diff --git a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java new file mode 100644 index 00000000000..c764ac50105 --- /dev/null +++ b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java @@ -0,0 +1,79 @@ +package org.sonar.batch.bootstrapper; + +import java.io.*; + +final class BootstrapperIOUtils { + + private BootstrapperIOUtils() { + } + + /** + * 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) { + // ignore + } + } + + /** + * 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; + } + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/Reactor.java b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/package-info.java index 7dd900b7e4c..7c23a7aa9ec 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/Reactor.java +++ b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/package-info.java @@ -17,22 +17,8 @@ * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ -package org.sonar.batch; -import org.apache.maven.project.MavenProject; - -import java.util.List; - -public class Reactor { - - private List<MavenProject> sortedProjects; - - public Reactor(List<MavenProject> sortedProjects) { - this.sortedProjects = sortedProjects; - } - - public List<MavenProject> getSortedProjects() { - return sortedProjects; - } - -} +/** + * Provides API to bootstrap Sonar Batch. + */ +package org.sonar.batch.bootstrapper;
\ No newline at end of file diff --git a/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BatchDownloaderTest.java b/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BatchDownloaderTest.java new file mode 100644 index 00000000000..1822a53f014 --- /dev/null +++ b/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BatchDownloaderTest.java @@ -0,0 +1,54 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + +import org.junit.Test; + +import java.io.IOException; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +public class BatchDownloaderTest { + + @Test + public void shouldRemoveLastUrlSlash() { + BatchDownloader bootstrapper = new BatchDownloader("http://test/"); + assertThat(bootstrapper.getServerUrl(), is("http://test")); + } + + @Test(expected = Exception.class) + public void shouldFailIfCanNotConnectServer() { + BatchDownloader bootstrapper = new BatchDownloader("http://unknown.foo"); + bootstrapper.getServerVersion(); + } + + @Test + public void shouldReturnValidVersion() { + BatchDownloader bootstrapper = new BatchDownloader("http://test") { + @Override + String remoteContent(String path) throws IOException { + return "2.6"; + } + }; + assertThat(bootstrapper.getServerVersion(), is("2.6")); + } + +} diff --git a/sonar-batch-maven-compat/pom.xml b/sonar-batch-maven-compat/pom.xml new file mode 100644 index 00000000000..1ebefa3e077 --- /dev/null +++ b/sonar-batch-maven-compat/pom.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar</artifactId> + <version>2.6-SNAPSHOT</version> + </parent> + + <artifactId>sonar-batch-maven-compat</artifactId> + <name>Sonar :: Batch Maven Compat</name> + <description>Compatibility layer, which provides MavenProject for non-Maven environments.</description> + + <dependencies> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + <version>2.0.7</version> + <scope>compile</scope> + <exclusions> + <exclusion> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-container-default</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml index fd1ae8dffb2..8c21ce740f7 100644 --- a/sonar-batch/pom.xml +++ b/sonar-batch/pom.xml @@ -11,7 +11,7 @@ <artifactId>sonar-batch</artifactId> <packaging>jar</packaging> <name>Sonar :: Batch</name> - + <dependencies> <dependency> <groupId>org.codehaus.sonar</groupId> diff --git a/sonar-batch/src/main/java/org/sonar/batch/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/Batch.java index bf5b1e348bd..373300542ec 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/Batch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/Batch.java @@ -25,6 +25,7 @@ import org.picocontainer.MutablePicoContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.Plugins; +import org.sonar.api.batch.maven.MavenPluginHandler; import org.sonar.api.resources.Project; import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.IocContainer; @@ -128,9 +129,32 @@ public class Batch { for (Object component : components) { register(container, component); } + if (!isMavenPluginExecutorRegistered()) { + register(container, FakeMavenPluginExecutor.class); + } return container; } + boolean isMavenPluginExecutorRegistered() { + for (Object component : components) { + if (component instanceof Class && MavenPluginExecutor.class.isAssignableFrom((Class<?>) component)) { + return true; + } + } + return false; + } + + class FakeMavenPluginExecutor implements MavenPluginExecutor { + public void execute(Project project, String goal) { + // do nothing + } + + public MavenPluginHandler execute(Project project, MavenPluginHandler handler) { + // do nothing + return handler; + } + } + private void register(MutablePicoContainer container, Object component) { container.as(Characteristics.CACHE).addComponent(component); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/MavenReactor.java b/sonar-batch/src/main/java/org/sonar/batch/MavenReactor.java index a33e6889ec8..1f0acf8c19e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/MavenReactor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/MavenReactor.java @@ -20,11 +20,24 @@ package org.sonar.batch; import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; -public class MavenReactor extends Reactor { +import java.util.List; + +public class MavenReactor { + + private List<MavenProject> sortedProjects; public MavenReactor(MavenSession mavenSession) { - super(mavenSession.getSortedProjects()); + this.sortedProjects = mavenSession.getSortedProjects(); + } + + public MavenReactor(List<MavenProject> sortedProjects) { + this.sortedProjects = sortedProjects; + } + + public List<MavenProject> getSortedProjects() { + return sortedProjects; } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java b/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java index 1f969befd10..8adf4987039 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ProjectTree.java @@ -19,8 +19,13 @@ */ package org.sonar.batch; +import org.sonar.batch.bootstrapper.ProjectDefinition; + +import org.sonar.batch.bootstrapper.Reactor; + import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.apache.maven.model.Reporting; import org.apache.maven.project.MavenProject; import org.slf4j.LoggerFactory; import org.sonar.api.database.DatabaseSession; @@ -36,12 +41,68 @@ public class ProjectTree { private List<MavenProject> poms; private MavenProjectBuilder projectBuilder; - public ProjectTree(Reactor reactor, DatabaseSession databaseSession) { - this.poms = reactor.getSortedProjects(); + public ProjectTree(MavenReactor mavenReactor, DatabaseSession databaseSession) { + this.poms = mavenReactor.getSortedProjects(); this.projectBuilder = new MavenProjectBuilder(databaseSession); } /** + * Hack for non-Maven environments. + */ + public ProjectTree(Reactor sonarReactor, DatabaseSession databaseSession) { + this(createMavenReactor(sonarReactor), databaseSession); + } + + private static MavenReactor createMavenReactor(Reactor sonarReactor) { + List<ProjectDefinition> sonarProjects = sonarReactor.getSortedProjects(); + List<MavenProject> mavenProjects = Lists.newArrayList(); + for (ProjectDefinition project : sonarProjects) { + mavenProjects.add(createInMemoryPom(project)); + } + return new MavenReactor(mavenProjects); + } + + private static MavenProject createInMemoryPom(ProjectDefinition project) { + MavenProject pom = new MavenProject(); + + String key = project.getProperties().getString("project.key"); // TODO constant + String[] keys = key.split(":"); + pom.setGroupId(keys[0]); + pom.setArtifactId(keys[1]); + pom.setVersion("0.1-SNAPSHOT"); // TODO hard-coded value + + pom.setArtifacts(Collections.EMPTY_SET); + + // Configure fake directories + String buildDirectory = project.getProperties().getString("project.build.directory"); + File sonarDir = new File(buildDirectory, "sonar"); + pom.setFile(new File(sonarDir, "fake-pom.xml")); + pom.getBuild().setDirectory(buildDirectory); + pom.getBuild().setOutputDirectory(buildDirectory + "/classes"); // TODO hard-coded value + Reporting reporting = new Reporting(); + reporting.setOutputDirectory(buildDirectory + "/target/site"); // TODO hard-coded value + pom.setReporting(reporting); + + // Configure source directories + // TODO + // for (FileSystemDirectory dir : project.getDirs()) { + // if (dir.getNature() == Natures.MAIN) { + // pom.addCompileSourceRoot(dir.getLocation().getAbsolutePath()); + // } + // } + + // Configure test directories + // TODO + // for (FileSystemDirectory dir : project.getDirs()) { + // if (dir.getNature() == Natures.TEST) { + // pom.addTestCompileSourceRoot(dir.getLocation().getAbsolutePath()); + // } + // } + + return pom; + } + + /** * for unit tests */ protected ProjectTree(MavenProjectBuilder projectBuilder, List<MavenProject> poms) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectDefinition.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectDefinition.java deleted file mode 100644 index d12dc1a9af1..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectDefinition.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.sonar.batch.bootstrap; - -import com.google.common.collect.Lists; -import org.apache.commons.configuration.Configuration; -import org.sonar.api.resources.FileSystemDirectory; - -import java.io.File; -import java.util.List; - -/** - * Defines project in a form suitable to bootstrap Sonar batch. - * We assume that project is just a set of configuration properties and directories. - * This is a part of bootstrap process, so we should take care about backward compatibility. - * - * @since 2.6 - */ -public class ProjectDefinition { - - private Configuration configuration; - - private File workDir; - private File basedir; - private List<FileSystemDirectory> dirs = Lists.newArrayList(); - - private ProjectDefinition parent; - private List<ProjectDefinition> modules; - - /** - * @return project properties. - */ - public Configuration getConfiguration() { - return configuration; - } - - public void setConfiguration(Configuration configuration) { - this.configuration = configuration; - } - - /** - * @return Sonar working directory for this project. - * It's "${project.build.directory}/sonar" ("${project.basedir}/target/sonar") for Maven projects. - */ - public File getSonarWorkingDirectory() { - return workDir; - } - - public void setSonarWorkingDirectory(File workDir) { - this.workDir = workDir; - } - - /** - * @return project root directory. - * It's "${project.basedir}" for Maven projects. - */ - public File getBasedir() { - return basedir; - } - - public void setBasedir(File basedir) { - this.basedir = basedir; - } - - /** - * @return project directories. - */ - public List<FileSystemDirectory> getDirs() { - return dirs; - } - - public void addDir(FileSystemDirectory dir) { - this.dirs.add(dir); - } - - /** - * @return parent project. - */ - public ProjectDefinition getParent() { - return parent; - } - - public void setParent(ProjectDefinition parent) { - this.parent = parent; - if (parent != null) { - parent.modules.add(this); - } - } - - /** - * @return list of sub-projects. - */ - public List<ProjectDefinition> getModules() { - return modules; - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/ProjectDefinition.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/ProjectDefinition.java new file mode 100644 index 00000000000..2b0a2a27205 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/ProjectDefinition.java @@ -0,0 +1,55 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + +import org.apache.commons.configuration.Configuration; + +import java.io.File; + +/** + * Defines project in a form suitable to bootstrap Sonar batch. + * We assume that project is just a set of configuration properties and directories. + * This is a part of bootstrap process, so we should take care about backward compatibility. + * + * @since 2.6 + */ +public class ProjectDefinition { + + private File baseDir; + private Configuration properties; + + /** + * @param baseDir project base directory + * @param properties project properties + */ + public ProjectDefinition(File baseDir, Configuration properties) { + this.baseDir = baseDir; + this.properties = properties; + } + + public File getBaseDir() { + return baseDir; + } + + public Configuration getProperties() { + return properties; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Reactor.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Reactor.java new file mode 100644 index 00000000000..909adedf847 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Reactor.java @@ -0,0 +1,48 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + + +import java.util.Collections; +import java.util.List; + +/** + * Defines order of projects. + * This is a part of bootstrap process, so we should take care about backward compatibility. + * + * @since 2.6 + */ +public class Reactor { + + private List<ProjectDefinition> projects; + + public Reactor(ProjectDefinition project) { + this.projects = Collections.singletonList(project); + } + + public Reactor(List<ProjectDefinition> sortedProjects) { + this.projects = sortedProjects; + } + + public List<ProjectDefinition> getSortedProjects() { + return projects; + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/BatchTest.java b/sonar-batch/src/test/java/org/sonar/batch/BatchTest.java new file mode 100644 index 00000000000..9f5fbb7a7b0 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/BatchTest.java @@ -0,0 +1,31 @@ +package org.sonar.batch; + +import org.junit.Test; +import org.sonar.api.batch.maven.MavenPluginHandler; +import org.sonar.api.resources.Project; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +public class BatchTest { + + class MyMavenPluginExecutor implements MavenPluginExecutor { + public void execute(Project project, String goal) { + } + + public MavenPluginHandler execute(Project project, MavenPluginHandler handler) { + return handler; + } + } + + @Test + public void shouldSearchMavenPluginExecutor() { + Batch batch; + + batch = new Batch(null, MyMavenPluginExecutor.class); + assertThat(batch.isMavenPluginExecutorRegistered(), is(true)); + + batch = new Batch(null); + assertThat(batch.isMavenPluginExecutorRegistered(), is(false)); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/DefaultFileSystemDirectory.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/DefaultFileSystemDirectory.java deleted file mode 100644 index 44461fb4772..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/DefaultFileSystemDirectory.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.api.resources; - -import com.google.common.collect.Lists; - -import java.io.File; -import java.util.Collections; -import java.util.List; - -public class DefaultFileSystemDirectory implements FileSystemDirectory { - - private String nature; - private File location; - private File outputLocation; - private List<String> inclusionPatterns; - private List<String> exclusionPatterns; - - public String getNature() { - return nature; - } - - public DefaultFileSystemDirectory setNature(String nature) { - this.nature = nature; - return this; - } - - public File getLocation() { - return location; - } - - public DefaultFileSystemDirectory setLocation(File location) { - this.location = location; - return this; - } - - public File getOutputLocation() { - return outputLocation; - } - - public DefaultFileSystemDirectory setOutputLocation(File outputLocation) { - this.outputLocation = outputLocation; - return this; - } - - public List<String> getInclusionPatterns() { - if (inclusionPatterns == null) { - return Collections.emptyList(); - } - return Collections.unmodifiableList(inclusionPatterns); - } - - /** - * @param pattern Ant-like inclusion pattern - */ - public DefaultFileSystemDirectory addInclusionPattern(String pattern) { - if (inclusionPatterns == null) { - inclusionPatterns = Lists.newArrayList(); - } - inclusionPatterns.add(pattern); - return this; - } - - public List<String> getExclusionPatterns() { - if (exclusionPatterns == null) { - return Collections.emptyList(); - } - return Collections.unmodifiableList(exclusionPatterns); - } - - /** - * @param pattern Ant-like exclusion pattern - */ - public DefaultFileSystemDirectory addExclusionPattern(String pattern) { - if (exclusionPatterns == null) { - exclusionPatterns = Lists.newArrayList(); - } - exclusionPatterns.add(pattern); - return this; - } -} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/FileSystemDirectory.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/FileSystemDirectory.java deleted file mode 100644 index 17c8298836c..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/FileSystemDirectory.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.api.resources; - - -import java.io.File; -import java.util.List; - -/** - * Defines project directory in a form suitable for Sonar. - * This is a part of bootstrap process, so we should take care about backward compatibility. - * <p> - * Couple of examples to show what this structure defines: - * <ul> - * <li>Typical Java project based on Ant might consist of two directories: - * <ol> - * <li>sources (location "src", output location "bin", includes "*.java")</li> - * <li>resources (location "src", output location "bin", excludes "*.java")</li> - * </ol> - * </li> - * <li>Typical Java project based on Maven might consist of four directories: - * <ol> - * <li>main sources (location "src/main/java", output location "target/classes")</li> - * <li>main resources (location "src/main/resources", output location "target/classes")</li> - * <li>test sources (location "src/test/java", output location "target/test-classes")</li> - * <li>test resources (location "src/test/resources", output location "target/test-classes")</li> - * </ol> - * </li> - * </ul> - * </p> - * - * @since 2.6 - */ -public interface FileSystemDirectory { - - /** - * @return nature of underlying files. - * @see Natures - */ - String getNature(); - - /** - * @return location of files for compilation. - * In case of Java this would be directory with Java source files. - */ - File getLocation(); - - /** - * @return location of binary files after compilation. - * In case of Java this would be directory with Class files. - */ - File getOutputLocation(); - - /** - * @return list of Ant-like inclusion patterns for files. - */ - List<String> getInclusionPatterns(); - - /** - * @return list of Ant-like exclusion patterns for files. - */ - List<String> getExclusionPatterns(); - -} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Natures.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Natures.java deleted file mode 100644 index 5b8f102fef6..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Natures.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.sonar.api.resources; - -/** - * @since 2.6 - */ -public interface Natures { - - /** - * Everything which relate to source code (for example "src/main/java" and "src/main/resources"). - */ - String MAIN = "MAIN"; - - /** - * Everything which relate to unit tests (for example "src/test/java" and "src/test/resources"). - */ - String TEST = "TEST"; - -} diff --git a/sonar-server/pom.xml b/sonar-server/pom.xml index a90ae860b18..b240684563c 100644 --- a/sonar-server/pom.xml +++ b/sonar-server/pom.xml @@ -11,6 +11,18 @@ <name>Sonar :: Server</name> <dependencies> + <!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!! TODO Review !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> + <dependency> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-batch</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-batch-maven-compat</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.codehaus.sonar</groupId> <artifactId>sonar-channel</artifactId> diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/BatchResourcesServlet.java b/sonar-server/src/main/java/org/sonar/server/plugins/BatchResourcesServlet.java new file mode 100644 index 00000000000..1e8ab666578 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/plugins/BatchResourcesServlet.java @@ -0,0 +1,104 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.server.plugins; + +import com.google.common.collect.Lists; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.List; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * This servlet allows to load libraries from directory "WEB-INF/lib" in order to provide them for batch-bootstrapper. + * Most probably this is not a best solution. + */ +public class BatchResourcesServlet extends HttpServlet { + + private static final Logger LOG = LoggerFactory.getLogger(BatchResourcesServlet.class); + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String resource = getResource(request); + if (StringUtils.isEmpty(resource)) { + PrintWriter writer = null; + try { + String libs = StringUtils.join(getLibs(), ","); + response.setContentType("text/html"); + writer = response.getWriter(); + writer.println(libs); + } catch (IOException e) { + LOG.error("Unable to provide list of batch resources", e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } finally { + IOUtils.closeQuietly(writer); + } + } else { + InputStream in = null; + OutputStream out = null; + try { + in = getServletContext().getResourceAsStream("/WEB-INF/lib/" + resource); + if (in == null) { + // TODO + } else { + out = response.getOutputStream(); + IOUtils.copy(in, out); + } + } catch (Exception e) { + LOG.error("Unable to load batch resource '" + resource + "'", e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } finally { + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(out); + } + } + } + + List<String> getLibs() { + List<String> libs = Lists.newArrayList(); + Set paths = getServletContext().getResourcePaths("/WEB-INF/lib"); + for (Object obj : paths) { + String path = (String) obj; + if (StringUtils.endsWith(path, ".jar")) { + libs.add(StringUtils.removeStart(path, "/WEB-INF/lib/")); + } + } + return libs; + } + + /** + * @return part of request URL after servlet path + */ + String getResource(HttpServletRequest request) { + return StringUtils.substringAfter(request.getRequestURI(), request.getContextPath() + request.getServletPath() + "/"); + } + +} diff --git a/sonar-server/src/main/webapp/WEB-INF/web.xml b/sonar-server/src/main/webapp/WEB-INF/web.xml index 99d68dcc5f6..25869629487 100644 --- a/sonar-server/src/main/webapp/WEB-INF/web.xml +++ b/sonar-server/src/main/webapp/WEB-INF/web.xml @@ -78,6 +78,10 @@ <servlet-name>static</servlet-name> <servlet-class>org.sonar.server.plugins.StaticResourcesServlet</servlet-class> </servlet> + <servlet> + <servlet-name>batch</servlet-name> + <servlet-class>org.sonar.server.plugins.BatchResourcesServlet</servlet-class> + </servlet> <servlet-mapping> <servlet-name>chart</servlet-name> @@ -91,6 +95,10 @@ <servlet-name>static</servlet-name> <url-pattern>/static/*</url-pattern> </servlet-mapping> + <servlet-mapping> + <servlet-name>batch</servlet-name> + <url-pattern>/batch/*</url-pattern> + </servlet-mapping> <listener> <listener-class>org.sonar.server.platform.PlatformLifecycleListener</listener-class> @@ -103,4 +111,4 @@ <session-timeout>30</session-timeout> </session-config> -</web-app>
\ No newline at end of file +</web-app> diff --git a/sonar-server/src/test/java/org/sonar/server/plugins/BatchResourcesServletTest.java b/sonar-server/src/test/java/org/sonar/server/plugins/BatchResourcesServletTest.java new file mode 100644 index 00000000000..3dadef9567f --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/plugins/BatchResourcesServletTest.java @@ -0,0 +1,59 @@ +package org.sonar.server.plugins; + +import com.google.common.collect.Sets; +import org.junit.Before; +import org.junit.Test; + +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +public class BatchResourcesServletTest { + private BatchResourcesServlet servlet; + private HttpServletRequest request; + + @Before + public void setUp() throws Exception { + servlet = new BatchResourcesServlet(); + request = mock(HttpServletRequest.class); + } + + @Test + public void shouldDetermineResource() { + when(request.getContextPath()).thenReturn("sonar"); + when(request.getServletPath()).thenReturn("/batch"); + + when(request.getRequestURI()).thenReturn("/sonar/batch/sonar-core-2.6.jar"); + assertThat(servlet.getResource(request), is("sonar-core-2.6.jar")); + + when(request.getRequestURI()).thenReturn("/sonar/batch/"); + assertThat(servlet.getResource(request), is("")); + + when(request.getRequestURI()).thenReturn("/sonar/batch"); + assertThat(servlet.getResource(request), is("")); + } + + @Test + public void shouldDetermineListOfResources() { + ServletContext servletContext = mock(ServletContext.class); + servlet = spy(servlet); + doReturn(servletContext).when(servlet).getServletContext(); + Set<String> libs = Sets.newHashSet(); + libs.add("/WEB-INF/lib/sonar-core-2.6.jar"); + libs.add("/WEB-INF/lib/treemap.rb"); + libs.add("/WEB-INF/lib/directory/"); + when(servletContext.getResourcePaths(anyString())).thenReturn(libs); + + assertThat(servlet.getLibs().size(), is(1)); + assertThat(servlet.getLibs().get(0), is("sonar-core-2.6.jar")); + } +} |