diff options
34 files changed, 982 insertions, 152 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AbstractTaskModule.java index bedc8578223..86199c7780d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AbstractTaskModule.java @@ -19,14 +19,12 @@ */ package org.sonar.batch.bootstrap; -import org.sonar.api.batch.InstantiationStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.TaskDefinition; import org.sonar.api.config.EmailSettings; -import org.sonar.api.resources.Project; import org.sonar.api.resources.ResourceTypes; -import org.sonar.batch.DefaultFileLinesContextFactory; import org.sonar.batch.DefaultResourceCreationLock; -import org.sonar.batch.ProjectConfigurator; -import org.sonar.batch.ProjectTree; import org.sonar.batch.components.PastMeasuresLoader; import org.sonar.batch.components.PastSnapshotFinder; import org.sonar.batch.components.PastSnapshotFinderByDate; @@ -34,7 +32,6 @@ import org.sonar.batch.components.PastSnapshotFinderByDays; import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis; import org.sonar.batch.components.PastSnapshotFinderByPreviousVersion; import org.sonar.batch.components.PastSnapshotFinderByVersion; -import org.sonar.batch.index.DefaultIndex; import org.sonar.batch.index.DefaultPersistenceManager; import org.sonar.batch.index.DefaultResourcePersister; import org.sonar.batch.index.DependencyPersister; @@ -48,9 +45,9 @@ import org.sonar.core.i18n.RuleI18nManager; import org.sonar.core.metric.CacheMetricFinder; import org.sonar.core.notification.DefaultNotificationManager; import org.sonar.core.persistence.DaoUtils; -import org.sonar.core.persistence.SemaphoresImpl; import org.sonar.core.persistence.DatabaseVersion; import org.sonar.core.persistence.MyBatis; +import org.sonar.core.persistence.SemaphoresImpl; import org.sonar.core.resource.DefaultResourcePermissions; import org.sonar.core.rule.CacheRuleFinder; import org.sonar.core.user.DefaultUserFinder; @@ -59,33 +56,39 @@ import org.sonar.jpa.session.DefaultDatabaseConnector; import org.sonar.jpa.session.JpaDatabaseSession; /** - * Level-2 components. Connected to database. + * Level-3 components. Task-level components that don't depends on project. */ -public class BatchModule extends Module { +public abstract class AbstractTaskModule extends Module { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractTaskModule.class); + + private TaskDefinition task; + + public AbstractTaskModule(TaskDefinition task) { + this.task = task; + } @Override protected void configure() { + logSettings(); + container.addSingleton(task.getExecutor()); registerCoreComponents(); registerDatabaseComponents(); - registerBatchExtensions(); + registerTaskExtensions(); } private void registerCoreComponents() { container.addSingleton(EmailSettings.class); container.addSingleton(I18nManager.class); container.addSingleton(RuleI18nManager.class); - container.addSingleton(ProjectExclusions.class); - container.addSingleton(ProjectReactorReady.class); - container.addSingleton(ProjectTree.class); - container.addSingleton(ProjectConfigurator.class); container.addSingleton(DefaultResourceCreationLock.class); - container.addSingleton(DefaultIndex.class); - container.addSingleton(DefaultFileLinesContextFactory.class); + container.addSingleton(DefaultPersistenceManager.class); container.addSingleton(DependencyPersister.class); container.addSingleton(EventPersister.class); container.addSingleton(LinkPersister.class); container.addSingleton(MeasurePersister.class); + container.addSingleton(MemoryOptimizer.class); container.addSingleton(DefaultResourcePermissions.class); container.addSingleton(DefaultResourcePersister.class); @@ -105,12 +108,10 @@ public class BatchModule extends Module { container.addSingleton(ResourceTypes.class); container.addSingleton(MetricProvider.class); container.addSingleton(SemaphoresImpl.class); - container.addSingleton(ProjectLock.class); } private void registerDatabaseComponents() { container.addSingleton(JdbcDriverHolder.class); - container.addSingleton(DryRunDatabase.class); container.addSingleton(BatchDatabase.class); container.addSingleton(MyBatis.class); container.addSingleton(DatabaseVersion.class); @@ -125,29 +126,21 @@ public class BatchModule extends Module { container.addSingleton(BatchDatabaseSessionFactory.class); } - private void registerBatchExtensions() { + private void registerTaskExtensions() { ExtensionInstaller installer = container.getComponentByType(ExtensionInstaller.class); - installer.install(container, InstantiationStrategy.PER_BATCH); + installer.installTaskExtensions(container); + } + + private void logSettings() { + LOG.info("------------- Executing {}", task.getTaskDescriptor().getName()); } + /** + * Execute task + */ @Override protected void doStart() { - ProjectTree projectTree = container.getComponentByType(ProjectTree.class); - analyze(projectTree.getRootProject()); + container.getComponentByType(task.getExecutor()).execute(); } - private void analyze(Project project) { - for (Project subProject : project.getModules()) { - analyze(subProject); - } - - ProjectModule projectModule = new ProjectModule(project); - try { - installChild(projectModule); - projectModule.start(); - } finally { - projectModule.stop(); - uninstallChild(); - } - } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalyseProjectModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalyseProjectModule.java new file mode 100644 index 00000000000..7752404cc09 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalyseProjectModule.java @@ -0,0 +1,65 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.bootstrap; + +import org.sonar.api.batch.InstantiationStrategy; +import org.sonar.api.resources.Project; + +public class AnalyseProjectModule extends Module { + + private Project rootProject; + + public AnalyseProjectModule(Project rootProject) { + this.rootProject = rootProject; + } + + @Override + protected void configure() { + registerBatchExtensions(); + } + + private void registerBatchExtensions() { + ExtensionInstaller installer = container.getComponentByType(ExtensionInstaller.class); + installer.installBatchExtensions(container, InstantiationStrategy.PER_BATCH); + } + + /** + * Analyze project + */ + @Override + protected void doStart() { + analyze(rootProject); + } + + private void analyze(Project project) { + for (Project subProject : project.getModules()) { + analyze(subProject); + } + + ProjectModule projectModule = new ProjectModule(rootProject); + try { + installChild(projectModule); + projectModule.start(); + } finally { + projectModule.stop(); + uninstallChild(); + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabase.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabase.java index 4d64d5523c6..351d1564fac 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabase.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchDatabase.java @@ -30,13 +30,20 @@ import java.util.Properties; public class BatchDatabase extends DefaultDatabase { public BatchDatabase(Settings settings, - // The dependency on JdbcDriverHolder is required to be sure that the JDBC driver - // has been downloaded and injected into classloader - JdbcDriverHolder jdbcDriverHolder, + // The dependency on JdbcDriverHolder is required to be sure that the JDBC driver + // has been downloaded and injected into classloader + JdbcDriverHolder jdbcDriverHolder, - // The dependency on DryRunDatabase is required to be sure that the dryRun mode - // changed settings - DryRunDatabase dryRun) { + // The dependency on DryRunDatabase is required to be sure that the dryRun mode + // changed settings + DryRunDatabase dryRun) { + super(settings); + } + + public BatchDatabase(Settings settings, + // The dependency on JdbcDriverHolder is required to be sure that the JDBC driver + // has been downloaded and injected into classloader + JdbcDriverHolder jdbcDriverHolder) { super(settings); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java index 811a1f71248..0987d020216 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchSettings.java @@ -42,36 +42,56 @@ public class BatchSettings extends Settings { // module key -> <key,val> private Map<String, Map<String, String>> moduleProperties = Maps.newHashMap(); + public BatchSettings(BootstrapSettings bootstrapSettings, PropertyDefinitions propertyDefinitions, + ServerClient client, Configuration deprecatedConfiguration, GlobalBatchProperties globalProperties) { + this(bootstrapSettings, propertyDefinitions, null, client, deprecatedConfiguration, globalProperties); + } + public BatchSettings(BootstrapSettings bootstrapSettings, PropertyDefinitions propertyDefinitions, ProjectReactor reactor, - ServerClient client, Configuration deprecatedConfiguration) { + ServerClient client, Configuration deprecatedConfiguration, GlobalBatchProperties globalProperties) { super(propertyDefinitions); this.deprecatedConfiguration = deprecatedConfiguration; - init(bootstrapSettings, reactor, client); + init(bootstrapSettings, reactor, client, globalProperties); } @VisibleForTesting BatchSettings() { } - private void init(BootstrapSettings bootstrapSettings, ProjectReactor reactor, ServerClient client) { - LoggerFactory.getLogger(BatchSettings.class).info("Load project settings"); + private void init(BootstrapSettings bootstrapSettings, ProjectReactor reactor, ServerClient client, + GlobalBatchProperties globalProperties) { + LoggerFactory.getLogger(BatchSettings.class).info("Load batch settings"); - String branch = bootstrapSettings.getProperty(CoreProperties.PROJECT_BRANCH_PROPERTY); - String projectKey = reactor.getRoot().getKey(); - if (StringUtils.isNotBlank(branch)) { - projectKey = String.format("%s:%s", projectKey, branch); + if (reactor != null) { + String branch = bootstrapSettings.getProperty(CoreProperties.PROJECT_BRANCH_PROPERTY); + String projectKey = reactor.getRoot().getKey(); + if (StringUtils.isNotBlank(branch)) { + projectKey = String.format("%s:%s", projectKey, branch); + } + downloadSettings(client, projectKey); + } + else { + downloadSettings(client, null); } - downloadSettings(client, projectKey); - // order is important -> bottom-up. The last one overrides all the others. - addProperties(reactor.getRoot().getProperties()); + addProperties(globalProperties.getProperties()); + if (reactor != null) { + addProperties(reactor.getRoot().getProperties()); + } addEnvironmentVariables(); addSystemProperties(); } private void downloadSettings(ServerClient client, String projectKey) { - String jsonText = client.request("/batch_bootstrap/properties?project=" + projectKey); + String url; + if (StringUtils.isNotBlank(projectKey)) { + url = "/batch_bootstrap/properties?project=" + projectKey; + } + else { + url = "/batch_bootstrap/properties"; + } + String jsonText = client.request(url); List<Map<String, String>> json = (List<Map<String, String>>) JSONValue.parse(jsonText); for (Map<String, String> jsonProperty : json) { String key = jsonProperty.get("k"); diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java index ee8b60c2058..6e2d80571c6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapModule.java @@ -34,15 +34,27 @@ public class BootstrapModule extends Module { private Object[] boostrapperComponents; private ProjectReactor reactor; + private GlobalBatchProperties globalProperties; + private String taskCommand; public BootstrapModule(ProjectReactor reactor, Object... boostrapperComponents) { + this(new GlobalBatchProperties(), null, reactor, boostrapperComponents); + } + + public BootstrapModule(GlobalBatchProperties globalProperties, String taskCommand, ProjectReactor reactor, + Object... boostrapperComponents) { + this.globalProperties = globalProperties; + this.taskCommand = taskCommand; this.reactor = reactor; this.boostrapperComponents = boostrapperComponents; } @Override protected void configure() { - container.addSingleton(reactor); + container.addSingleton(globalProperties); + if (reactor != null) { + container.addSingleton(reactor); + } container.addSingleton(new PropertiesConfiguration()); container.addSingleton(BootstrapSettings.class); container.addSingleton(ServerClient.class); @@ -79,7 +91,7 @@ public class BootstrapModule extends Module { @Override protected void doStart() { - Module batchComponents = installChild(new BatchModule()); - batchComponents.start(); + Module taskBootstrap = installChild(new TaskBootstrapModule(taskCommand)); + taskBootstrap.start(); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java index b09b33bddca..616219730ff 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapSettings.java @@ -32,15 +32,22 @@ import java.util.Properties; public class BootstrapSettings { private Map<String, String> properties; - public BootstrapSettings(ProjectReactor reactor) { - init(reactor); + public BootstrapSettings(GlobalBatchProperties globalProperties) { + init(null, globalProperties); } - private void init(ProjectReactor reactor) { + public BootstrapSettings(ProjectReactor reactor, GlobalBatchProperties globalProperties) { + init(reactor, globalProperties); + } + + private void init(ProjectReactor reactor, GlobalBatchProperties globalProperties) { properties = Maps.newHashMap(); // order is important -> bottom-up. The last one overrides all the others. - addProperties(reactor.getRoot().getProperties()); + properties.putAll(globalProperties.getProperties()); + if (reactor != null) { + addProperties(reactor.getRoot().getProperties()); + } properties.putAll(System.getenv()); addProperties(System.getProperties()); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java index b480a2447c7..068a2b69730 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java @@ -19,6 +19,8 @@ */ package org.sonar.batch.bootstrap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; import org.sonar.api.CoreProperties; import org.sonar.api.ExtensionProvider; @@ -37,6 +39,8 @@ import java.util.Map; public class ExtensionInstaller implements BatchComponent { + private static final Logger LOG = LoggerFactory.getLogger(ExtensionInstaller.class); + private BatchPluginRepository pluginRepository; private EnvironmentInformation environment; private Settings settings; @@ -47,7 +51,101 @@ public class ExtensionInstaller implements BatchComponent { this.settings = settings; } - public void install(ComponentContainer container, String instantiationStrategy) { + public void installTaskDefinitionExtensions(ComponentContainer container) { + for (Map.Entry<PluginMetadata, Plugin> entry : pluginRepository.getPluginsByMetadata().entrySet()) { + PluginMetadata metadata = entry.getKey(); + Plugin plugin = entry.getValue(); + + container.addExtension(metadata, plugin); + for (Object extension : plugin.getExtensions()) { + installTaskDefinition(container, metadata, extension); + } + } + + List<ExtensionProvider> providers = container.getComponentsByType(ExtensionProvider.class); + for (ExtensionProvider provider : providers) { + executeTaskDefinitionExtensionProvider(container, provider); + } + } + + private void executeTaskDefinitionExtensionProvider(ComponentContainer container, ExtensionProvider provider) { + Object obj = provider.provide(); + if (obj instanceof Iterable) { + for (Object extension : (Iterable) obj) { + installTaskDefinition(container, null, extension); + } + } else { + installTaskDefinition(container, null, obj); + } + } + + boolean installTaskDefinition(ComponentContainer container, @Nullable PluginMetadata plugin, Object extension) { + boolean installed; + if (ExtensionUtils.isTaskDefinitionExtension(extension) && + ExtensionUtils.supportsEnvironment(extension, environment)) { + if (plugin != null) { + LOG.debug("Installing task definition extension {} from plugin {}", extension.toString(), plugin.getKey()); + } + else { + LOG.debug("Installing task definition extension {}", extension.toString()); + } + container.addExtension(plugin, extension); + installed = true; + } else { + container.declareExtension(plugin, extension); + installed = false; + } + return installed; + } + + public void installTaskExtensions(ComponentContainer container) { + for (Map.Entry<PluginMetadata, Plugin> entry : pluginRepository.getPluginsByMetadata().entrySet()) { + PluginMetadata metadata = entry.getKey(); + Plugin plugin = entry.getValue(); + + container.addExtension(metadata, plugin); + for (Object extension : plugin.getExtensions()) { + installTaskExtension(container, metadata, extension); + } + } + + List<ExtensionProvider> providers = container.getComponentsByType(ExtensionProvider.class); + for (ExtensionProvider provider : providers) { + executeTaskExtensionProvider(container, provider); + } + } + + private void executeTaskExtensionProvider(ComponentContainer container, ExtensionProvider provider) { + Object obj = provider.provide(); + if (obj instanceof Iterable) { + for (Object extension : (Iterable) obj) { + installTaskExtension(container, null, extension); + } + } else { + installTaskExtension(container, null, obj); + } + } + + boolean installTaskExtension(ComponentContainer container, @Nullable PluginMetadata plugin, Object extension) { + boolean installed; + if (ExtensionUtils.isTaskExtension(extension) && + ExtensionUtils.supportsEnvironment(extension, environment)) { + if (plugin != null) { + LOG.debug("Installing task extension {} from plugin {}", extension.toString(), plugin.getKey()); + } + else { + LOG.debug("Installing task extension {}", extension.toString()); + } + container.addExtension(plugin, extension); + installed = true; + } else { + container.declareExtension(plugin, extension); + installed = false; + } + return installed; + } + + public void installBatchExtensions(ComponentContainer container, String instantiationStrategy) { boolean dryRun = settings.getBoolean(CoreProperties.DRY_RUN); for (Map.Entry<PluginMetadata, Plugin> entry : pluginRepository.getPluginsByMetadata().entrySet()) { PluginMetadata metadata = entry.getKey(); @@ -55,35 +153,40 @@ public class ExtensionInstaller implements BatchComponent { container.addExtension(metadata, plugin); for (Object extension : plugin.getExtensions()) { - installExtension(container, metadata, extension, dryRun, instantiationStrategy); + installBatchExtension(container, metadata, extension, dryRun, instantiationStrategy); } } List<ExtensionProvider> providers = container.getComponentsByType(ExtensionProvider.class); for (ExtensionProvider provider : providers) { - executeProvider(container, instantiationStrategy, dryRun, provider); + executeBatchExtensionProvider(container, instantiationStrategy, dryRun, provider); } } - private void executeProvider(ComponentContainer container, String instantiationStrategy, boolean dryRun, ExtensionProvider provider) { + private void executeBatchExtensionProvider(ComponentContainer container, String instantiationStrategy, boolean dryRun, ExtensionProvider provider) { Object obj = provider.provide(); if (obj instanceof Iterable) { for (Object extension : (Iterable) obj) { - installExtension(container, null, extension, dryRun, instantiationStrategy); + installBatchExtension(container, null, extension, dryRun, instantiationStrategy); } } else { - installExtension(container, null, obj, dryRun, instantiationStrategy); + installBatchExtension(container, null, obj, dryRun, instantiationStrategy); } } - boolean installExtension(ComponentContainer container, @Nullable PluginMetadata plugin, Object extension, boolean dryRun, String instantiationStrategy) { + boolean installBatchExtension(ComponentContainer container, @Nullable PluginMetadata plugin, Object extension, boolean dryRun, String instantiationStrategy) { boolean installed; if (ExtensionUtils.isBatchExtension(extension) && ExtensionUtils.supportsEnvironment(extension, environment) && (!dryRun || ExtensionUtils.supportsDryRun(extension)) && ExtensionUtils.isInstantiationStrategy(extension, instantiationStrategy) && !isMavenExtensionOnEmulatedMavenProject(extension, instantiationStrategy, container)) { - + if (plugin != null) { + LOG.debug("Installing batch extension {} from plugin {}", extension.toString(), plugin.getKey()); + } + else { + LOG.debug("Installing batch extension {}", extension.toString()); + } container.addExtension(plugin, extension); installed = true; } else { @@ -101,7 +204,7 @@ public class ExtensionInstaller implements BatchComponent { static boolean isMavenExtensionOnEmulatedMavenProject(Object extension, String instantiationStrategy, ComponentContainer container) { if (InstantiationStrategy.PER_PROJECT.equals(instantiationStrategy) && ExtensionUtils.isMavenExtensionOnly(extension)) { Project project = container.getComponentByType(Project.class); - return project!=null && project.getPom()==null; + return project != null && project.getPom() == null; } return false; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionUtils.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionUtils.java index 65d50ae8c41..fd6a1ba2252 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionUtils.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionUtils.java @@ -22,11 +22,13 @@ package org.sonar.batch.bootstrap; import org.apache.commons.lang.StringUtils; import org.sonar.api.BatchExtension; import org.sonar.api.Extension; -import org.sonar.core.DryRunIncompatible; +import org.sonar.api.TaskDefinitionExtension; +import org.sonar.api.TaskExtension; import org.sonar.api.batch.InstantiationStrategy; import org.sonar.api.batch.SupportedEnvironment; import org.sonar.api.utils.AnnotationUtils; import org.sonar.batch.bootstrapper.EnvironmentInformation; +import org.sonar.core.DryRunIncompatible; final class ExtensionUtils { @@ -42,6 +44,14 @@ final class ExtensionUtils { return InstantiationStrategy.PER_PROJECT.equals(strategy); } + static boolean isTaskDefinitionExtension(Object extension) { + return isType(extension, TaskDefinitionExtension.class); + } + + static boolean isTaskExtension(Object extension) { + return isType(extension, TaskExtension.class); + } + static boolean isBatchExtension(Object extension) { return isType(extension, BatchExtension.class); } @@ -65,7 +75,7 @@ final class ExtensionUtils { static boolean isMavenExtensionOnly(Object extension) { SupportedEnvironment env = AnnotationUtils.getAnnotation(extension, SupportedEnvironment.class); - return env!=null && env.value().length==1 && StringUtils.equalsIgnoreCase("maven", env.value()[0]); + return env != null && env.value().length == 1 && StringUtils.equalsIgnoreCase("maven", env.value()[0]); } static boolean isType(Object extension, Class<? extends Extension> extensionClass) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalBatchProperties.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalBatchProperties.java new file mode 100644 index 00000000000..2eade47658a --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalBatchProperties.java @@ -0,0 +1,48 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.bootstrap; + +import com.google.common.collect.Maps; + +import java.util.Map; + +/** + * Batch properties that are not specific to a project (for example + * coming from global configuration file of sonar-runner). + * @author Julien HENRY + * + */ +public class GlobalBatchProperties { + + protected final Map<String, String> properties; + + public GlobalBatchProperties() { + this.properties = Maps.newHashMap(); + } + + public GlobalBatchProperties(Map<String, String> properties) { + this.properties = Maps.newHashMap(properties); + } + + public Map<String, String> getProperties() { + return properties; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java index 80567137eff..0b3bfb9c2d3 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/Module.java @@ -40,7 +40,7 @@ public abstract class Module { /** * @return this */ - private void init(ComponentContainer container) { + public final void init(ComponentContainer container) { this.container = container; configure(); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java index 26f6893c2dd..e2c9c53db01 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectExclusions.java @@ -43,8 +43,8 @@ public class ProjectExclusions implements BatchComponent { private ProjectReactor reactor; public ProjectExclusions(Settings settings, ProjectReactor reactor, - // exclusions are applied when the project is completely defined by extensions - ProjectBuilder[] projectBuilders) { + // exclusions are applied when the project is completely defined by extensions + ProjectBuilder[] projectBuilders) { this.settings = settings; this.reactor = reactor; } @@ -54,10 +54,12 @@ public class ProjectExclusions implements BatchComponent { } public void start() { - LOG.info("Apply project exclusions"); - for (ProjectDefinition project : reactor.getProjects()) { - if (isExcluded(key(project), project == reactor.getRoot())) { - exclude(project); + if (reactor.getProjects().size() > 0 && StringUtils.isNotBlank(reactor.getProjects().get(0).getKey())) { + LOG.info("Apply project exclusions"); + for (ProjectDefinition project : reactor.getProjects()) { + if (isExcluded(key(project), project == reactor.getRoot())) { + exclude(project); + } } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLessTaskModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLessTaskModule.java new file mode 100644 index 00000000000..75f932deeb1 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLessTaskModule.java @@ -0,0 +1,35 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.bootstrap; + +import org.sonar.api.batch.TaskDefinition; + +public class ProjectLessTaskModule extends AbstractTaskModule { + + public ProjectLessTaskModule(TaskDefinition task) { + super(task); + } + + @Override + protected void configure() { + super.configure(); + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLock.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLock.java index 33a4620a4fc..b0bd127b6d7 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLock.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectLock.java @@ -19,6 +19,7 @@ */ package org.sonar.batch.bootstrap; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; @@ -43,7 +44,7 @@ public class ProjectLock { } public void start() { - if (!isInDryRunMode()) { + if (!isInDryRunMode() && StringUtils.isNotBlank(getProject().getKey())) { Semaphores.Semaphore semaphore = acquire(); if (!semaphore.isLocked()) { LOG.error(getErrorMessage(semaphore)); diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java index 3f58c74ccdf..bb7df9a5ed0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectModule.java @@ -107,7 +107,7 @@ public class ProjectModule extends Module { private void addPluginExtensions() { ExtensionInstaller installer = container.getComponentByType(ExtensionInstaller.class); - installer.install(container, InstantiationStrategy.PER_PROJECT); + installer.installBatchExtensions(container, InstantiationStrategy.PER_PROJECT); } private void logSettings() { @@ -122,9 +122,9 @@ public class ProjectModule extends Module { protected void doStart() { DefaultIndex index = container.getComponentByType(DefaultIndex.class); index.setCurrentProject(project, - container.getComponentByType(ResourceFilters.class), - container.getComponentByType(ViolationFilters.class), - container.getComponentByType(RulesProfile.class)); + container.getComponentByType(ResourceFilters.class), + container.getComponentByType(ViolationFilters.class), + container.getComponentByType(RulesProfile.class)); container.getComponentByType(Phases.class).execute(project); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTaskModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTaskModule.java new file mode 100644 index 00000000000..a7c7d3b97ee --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ProjectTaskModule.java @@ -0,0 +1,51 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.bootstrap; + +import org.sonar.api.batch.TaskDefinition; +import org.sonar.batch.DefaultFileLinesContextFactory; +import org.sonar.batch.ProjectConfigurator; +import org.sonar.batch.ProjectTree; +import org.sonar.batch.index.DefaultIndex; + +public class ProjectTaskModule extends AbstractTaskModule { + + public ProjectTaskModule(TaskDefinition task) { + super(task); + } + + @Override + protected void configure() { + super.configure(); + registerCoreComponentsRequiringProject(); + } + + private void registerCoreComponentsRequiringProject() { + container.addSingleton(ProjectExclusions.class); + container.addSingleton(ProjectReactorReady.class); + container.addSingleton(ProjectTree.class); + container.addSingleton(ProjectConfigurator.class); + container.addSingleton(DefaultIndex.class); + container.addSingleton(DefaultFileLinesContextFactory.class); + container.addSingleton(ProjectLock.class); + + container.addSingleton(DryRunDatabase.class); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskBootstrapModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskBootstrapModule.java new file mode 100644 index 00000000000..398ae8ba86e --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskBootstrapModule.java @@ -0,0 +1,84 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.bootstrap; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.batch.TaskDefinition; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.utils.SonarException; +import org.sonar.batch.tasks.AnalyseProjectTaskDefinition; +import org.sonar.batch.tasks.HelloWorldTask; +import org.sonar.batch.tasks.TaskManager; + +/** + * Level-2 components. Collect tasks definitions. + */ +public class TaskBootstrapModule extends Module { + + private String taskCommand; + + public TaskBootstrapModule(String taskCommand) { + this.taskCommand = taskCommand; + } + + @Override + protected void configure() { + registerCoreTaskDefinitions(); + registerTaskDefinitionExtensions(); + container.addSingleton(TaskManager.class); + } + + private void registerCoreTaskDefinitions() { + container.addSingleton(AnalyseProjectTaskDefinition.class); + container.addSingleton(HelloWorldTask.class); + } + + private void registerTaskDefinitionExtensions() { + ExtensionInstaller installer = container.getComponentByType(ExtensionInstaller.class); + installer.installTaskDefinitionExtensions(container); + } + + @Override + protected void doStart() { + String command = StringUtils.isNotBlank(taskCommand) ? taskCommand : AnalyseProjectTaskDefinition.COMMAND; + TaskManager manager = container.getComponentByType(TaskManager.class); + executeTask(manager.getTask(command)); + } + + private void executeTask(TaskDefinition task) { + if (task.getTaskDescriptor().isRequiresProject() && container.getComponentByType(ProjectReactor.class) == null) { + throw new SonarException("Task " + task.getTaskDescriptor().getName() + " requires to be run on a project"); + } + Module childModule; + if (task.getTaskDescriptor().isRequiresProject()) { + childModule = new ProjectTaskModule(task); + } + else { + childModule = new ProjectLessTaskModule(task); + } + try { + installChild(childModule); + childModule.start(); + } finally { + childModule.stop(); + uninstallChild(); + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java index 0970bd5bc55..b890f440824 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java @@ -24,11 +24,13 @@ import com.google.common.collect.Maps; import org.slf4j.LoggerFactory; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.batch.bootstrap.BootstrapModule; +import org.sonar.batch.bootstrap.GlobalBatchProperties; import org.sonar.batch.bootstrap.Module; import org.sonar.core.PicoUtils; import java.util.Collections; import java.util.List; +import java.util.Map; /** * Entry point for batch bootstrappers. @@ -39,12 +41,18 @@ public final class Batch { private LoggingConfiguration logging; private List<Object> components; + private Map<String, String> globalProperties = Maps.newHashMap(); + private String taskCommand; private ProjectReactor projectReactor; private Batch(Builder builder) { components = Lists.newArrayList(); components.addAll(builder.components); components.add(builder.environment); + if (builder.globalProperties != null) { + globalProperties.putAll(builder.globalProperties); + } + this.taskCommand = builder.taskCommand; projectReactor = builder.projectReactor; if (builder.isEnableLoggingConfiguration()) { logging = LoggingConfiguration.create().setProperties(Maps.fromProperties(projectReactor.getRoot().getProperties())); @@ -70,7 +78,8 @@ public final class Batch { private void startBatch() { Module bootstrapModule = null; try { - bootstrapModule = new BootstrapModule(projectReactor, components.toArray(new Object[components.size()])); + bootstrapModule = new BootstrapModule(new GlobalBatchProperties(globalProperties), taskCommand, + projectReactor, components.toArray(new Object[components.size()])); bootstrapModule.init(); bootstrapModule.start(); } catch (RuntimeException e) { @@ -87,12 +96,13 @@ public final class Batch { } } - public static Builder builder() { return new Builder(); } public static final class Builder { + private Map<String, String> globalProperties; + private String taskCommand; private ProjectReactor projectReactor; private EnvironmentInformation environment; private List<Object> components = Lists.newArrayList(); @@ -116,6 +126,16 @@ public final class Batch { return this; } + public Builder setGlobalProperties(Map<String, String> globalProperties) { + this.globalProperties = globalProperties; + return this; + } + + public Builder setTaskCommand(String taskCommand) { + this.taskCommand = taskCommand; + return this; + } + public Builder addComponents(Object... components) { Collections.addAll(this.components, components); return this; @@ -140,9 +160,6 @@ public final class Batch { } public Batch build() { - if (projectReactor == null) { - throw new IllegalStateException("ProjectReactor is not set"); - } if (environment == null) { throw new IllegalStateException("EnvironmentInfo is not set"); } @@ -152,4 +169,4 @@ public final class Batch { return new Batch(this); } } -}
\ No newline at end of file +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java index 79e4e2db95d..fee88556e8b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java @@ -89,7 +89,9 @@ public class DefaultIndex extends SonarIndex { public void start() { Project rootProject = projectTree.getRootProject(); - doStart(rootProject); + if (StringUtils.isNotBlank(rootProject.getKey())) { + doStart(rootProject); + } } void doStart(Project rootProject) { @@ -463,10 +465,10 @@ public class DefaultIndex extends SonarIndex { if (!StringUtils.equals(Scopes.PROJECT, resource.getScope())) { // not a project nor a library uid = new StringBuilder(ResourceModel.KEY_SIZE) - .append(project.getKey()) - .append(':') - .append(resource.getKey()) - .toString(); + .append(project.getKey()) + .append(':') + .append(resource.getKey()) + .toString(); } return uid; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/tasks/AnalyseProjectTaskDefinition.java b/sonar-batch/src/main/java/org/sonar/batch/tasks/AnalyseProjectTaskDefinition.java new file mode 100644 index 00000000000..a1284efe54e --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/tasks/AnalyseProjectTaskDefinition.java @@ -0,0 +1,42 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.tasks; + +import org.sonar.api.batch.TaskDefinition; +import org.sonar.api.batch.TaskDescriptor; +import org.sonar.api.batch.TaskExecutor; + +public class AnalyseProjectTaskDefinition implements TaskDefinition { + + public static final String COMMAND = "analyse-project"; + + public TaskDescriptor getTaskDescriptor() { + return TaskDescriptor.create() + .setDescription("Analysis") + .setName("Analysis") + .setCommand(COMMAND) + .setRequiresProject(true); + } + + public Class<? extends TaskExecutor> getExecutor() { + return AnalyseProjectTaskExecutor.class; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/tasks/AnalyseProjectTaskExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/tasks/AnalyseProjectTaskExecutor.java new file mode 100644 index 00000000000..4f76e5f72c3 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/tasks/AnalyseProjectTaskExecutor.java @@ -0,0 +1,49 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.tasks; + +import org.sonar.api.batch.TaskExecutor; +import org.sonar.api.platform.ComponentContainer; +import org.sonar.batch.ProjectTree; +import org.sonar.batch.bootstrap.AnalyseProjectModule; + +public class AnalyseProjectTaskExecutor implements TaskExecutor { + + private final ComponentContainer container; + private final ProjectTree projectTree; + + public AnalyseProjectTaskExecutor(ProjectTree projectTree, ComponentContainer container) { + this.container = container; + this.projectTree = projectTree; + } + + public void execute() { + AnalyseProjectModule analyseProjectModule = new AnalyseProjectModule(projectTree.getRootProject()); + try { + ComponentContainer childContainer = container.createChild(); + analyseProjectModule.init(childContainer); + analyseProjectModule.start(); + } finally { + analyseProjectModule.stop(); + container.removeChild(); + } + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/tasks/HelloWorldTask.java b/sonar-batch/src/main/java/org/sonar/batch/tasks/HelloWorldTask.java new file mode 100644 index 00000000000..79ec7fbb48f --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/tasks/HelloWorldTask.java @@ -0,0 +1,48 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.tasks; + +import org.sonar.api.batch.TaskDefinition; +import org.sonar.api.batch.TaskDescriptor; +import org.sonar.api.batch.TaskExecutor; + +public class HelloWorldTask implements TaskExecutor, TaskDefinition { + + public static final String COMMAND = "hello-world"; + + public HelloWorldTask() { + } + + public void execute() { + System.out.println("HELLO WORLD"); + } + + public TaskDescriptor getTaskDescriptor() { + return TaskDescriptor.create() + .setDescription("Hello World") + .setName("Hello") + .setCommand(COMMAND); + } + + public Class<? extends TaskExecutor> getExecutor() { + return HelloWorldTask.class; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/tasks/TaskManager.java b/sonar-batch/src/main/java/org/sonar/batch/tasks/TaskManager.java new file mode 100644 index 00000000000..c518d2fde96 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/tasks/TaskManager.java @@ -0,0 +1,42 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.tasks; + +import org.sonar.api.batch.TaskDefinition; +import org.sonar.api.utils.SonarException; + +public class TaskManager { + + private final TaskDefinition[] tasks; + + public TaskManager(TaskDefinition[] tasks) { + this.tasks = tasks; + } + + public TaskDefinition getTask(String command) { + for (TaskDefinition task : tasks) { + if (command.equals(task.getTaskDescriptor().getCommand())) { + return task; + } + } + throw new SonarException("No task found for command: " + command); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchModuleTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/AnalyseProjectModuleTest.java index 670c558bd00..2b47d832dea 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchModuleTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/AnalyseProjectModuleTest.java @@ -23,13 +23,12 @@ import org.junit.Test; import org.sonar.api.batch.InstantiationStrategy; import org.sonar.api.platform.ComponentContainer; -import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class BatchModuleTest { +public class AnalyseProjectModuleTest { @Test public void should_register_batch_extensions() { final ExtensionInstaller extensionInstaller = mock(ExtensionInstaller.class); @@ -41,10 +40,9 @@ public class BatchModuleTest { } }; bootstrapModule.init(); - BatchModule module = new BatchModule(); + AnalyseProjectModule module = new AnalyseProjectModule(null); bootstrapModule.installChild(module); - verify(extensionInstaller).install(any(ComponentContainer.class), eq(InstantiationStrategy.PER_BATCH)); - assertThat(module.container.getComponentByType(MetricProvider.class)).isNotNull(); + verify(extensionInstaller).installBatchExtensions(any(ComponentContainer.class), eq(InstantiationStrategy.PER_BATCH)); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java index 59b85e28bfa..8bc15a5756a 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchSettingsTest.java @@ -49,42 +49,42 @@ public class BatchSettingsTest { deprecatedConf = new BaseConfiguration(); client = mock(ServerClient.class); when(client.request("/batch_bootstrap/properties?project=struts")).thenReturn( - "[{\"k\":\"sonar.cpd.cross\",\"v\":\"true\"}," + - "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"jacoco\",\"p\":\"struts\"}," + - "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"cobertura\",\"p\":\"struts-core\"}]" - ); - bootstrapSettings = new BootstrapSettings(reactor); + "[{\"k\":\"sonar.cpd.cross\",\"v\":\"true\"}," + + "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"jacoco\",\"p\":\"struts\"}," + + "{\"k\":\"sonar.java.coveragePlugin\",\"v\":\"cobertura\",\"p\":\"struts-core\"}]" + ); + bootstrapSettings = new BootstrapSettings(reactor, new GlobalBatchProperties()); } @Test public void should_load_system_props() { System.setProperty("BatchSettingsTest.testSystemProp", "system"); - BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); assertThat(batchSettings.getString("BatchSettingsTest.testSystemProp")).isEqualTo("system"); } @Test public void should_load_build_props() { project.setProperty("build.prop", "build"); - BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); assertThat(batchSettings.getString("build.prop")).isEqualTo("build"); } @Test public void should_load_global_settings() { - BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); assertThat(batchSettings.getBoolean("sonar.cpd.cross")).isTrue(); } @Test public void should_load_project_root_settings() { - BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); assertThat(batchSettings.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco"); } @Test public void should_keep_module_settings_for_later() { - BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); Map<String, String> moduleSettings = batchSettings.getModuleProperties("struts-core"); assertThat(moduleSettings).hasSize(1); assertThat(moduleSettings.get("sonar.java.coveragePlugin")).isEqualTo("cobertura"); @@ -94,13 +94,13 @@ public class BatchSettingsTest { public void system_props_should_override_build_props() { System.setProperty("BatchSettingsTest.testSystemProp", "system"); project.setProperty("BatchSettingsTest.testSystemProp", "build"); - BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); assertThat(batchSettings.getString("BatchSettingsTest.testSystemProp")).isEqualTo("system"); } @Test public void should_forward_to_deprecated_commons_configuration() { - BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf); + BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); assertThat(deprecatedConf.getString("sonar.cpd.cross")).isEqualTo("true"); assertThat(deprecatedConf.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco"); diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapSettingsTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapSettingsTest.java index 9f2d807bff8..bc0af74b2a3 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapSettingsTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapSettingsTest.java @@ -34,7 +34,7 @@ public class BootstrapSettingsTest { project.setProperty("foo", "bar"); ProjectReactor reactor = new ProjectReactor(project); - BootstrapSettings settings = new BootstrapSettings(reactor); + BootstrapSettings settings = new BootstrapSettings(reactor, new GlobalBatchProperties()); assertThat(settings.getProperty("foo")).isEqualTo("bar"); } @@ -46,7 +46,7 @@ public class BootstrapSettingsTest { System.setProperty("BootstrapSettingsTest.testEnv", "env"); ProjectReactor reactor = new ProjectReactor(project); - BootstrapSettings settings = new BootstrapSettings(reactor); + BootstrapSettings settings = new BootstrapSettings(reactor, new GlobalBatchProperties()); assertThat(settings.getProperty("BootstrapSettingsTest.testEnv")).isEqualTo("env"); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java index 90f4981efdb..b8d2a1d9cff 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java @@ -49,12 +49,12 @@ public class ExtensionInstallerTest { private static Map<PluginMetadata, Plugin> newPlugin(final Class... classes) { Map<PluginMetadata, Plugin> result = Maps.newHashMap(); result.put(METADATA, - new SonarPlugin() { - public List<Class> getExtensions() { - return Arrays.asList(classes); + new SonarPlugin() { + public List<Class> getExtensions() { + return Arrays.asList(classes); + } } - } - ); + ); return result; } @@ -65,7 +65,7 @@ public class ExtensionInstallerTest { ComponentContainer container = new ComponentContainer(); ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); - installer.install(container, InstantiationStrategy.PER_BATCH); + installer.installBatchExtensions(container, InstantiationStrategy.PER_BATCH); assertThat(container.getComponentByType(BatchService.class)).isNotNull(); assertThat(container.getComponentByType(ProjectService.class)).isNull(); @@ -79,14 +79,13 @@ public class ExtensionInstallerTest { ComponentContainer container = new ComponentContainer(); ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); - installer.install(container, InstantiationStrategy.PER_BATCH); + installer.installBatchExtensions(container, InstantiationStrategy.PER_BATCH); assertThat(container.getComponentByType(BatchService.class)).isNotNull(); assertThat(container.getComponentByType(ProjectService.class)).isNull(); assertThat(container.getComponentByType(ServerService.class)).isNull(); } - @Test public void shouldNotInstallPluginsOnNonSupportedEnvironment() { BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); @@ -95,7 +94,7 @@ public class ExtensionInstallerTest { ComponentContainer container = new ComponentContainer(); ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); - installer.install(container, InstantiationStrategy.PER_PROJECT); + installer.installBatchExtensions(container, InstantiationStrategy.PER_PROJECT); assertThat(container.getComponentByType(MavenService.class)).isNull(); assertThat(container.getComponentByType(BuildToolService.class)).isNotNull(); @@ -112,7 +111,7 @@ public class ExtensionInstallerTest { container.addSingleton(project); ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("maven", "2.2.1"), new Settings()); - installer.install(container, InstantiationStrategy.PER_PROJECT); + installer.installBatchExtensions(container, InstantiationStrategy.PER_PROJECT); assertThat(container.getComponentByType(MavenService.class)).isNull(); } @@ -135,7 +134,7 @@ public class ExtensionInstallerTest { @Override public Object provide() { - return Arrays.<Object>asList(BatchService.class, ServerService.class); + return Arrays.<Object> asList(BatchService.class, ServerService.class); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java index bf108882e4c..6d26b4978a7 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ProjectModuleTest.java @@ -64,7 +64,7 @@ public class ProjectModuleTest { ProjectModule projectModule = new ProjectModule(project); batchModule.installChild(projectModule); - verify(extensionInstaller).install(any(ComponentContainer.class), eq(InstantiationStrategy.PER_PROJECT)); + verify(extensionInstaller).installBatchExtensions(any(ComponentContainer.class), eq(InstantiationStrategy.PER_PROJECT)); assertThat(projectModule.container.getComponentByType(ProjectSettings.class)).isNotNull(); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/BatchTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/BatchTest.java index eeb52de2918..653d5f5ff1e 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/BatchTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrapper/BatchTest.java @@ -20,12 +20,11 @@ package org.sonar.batch.bootstrapper; import org.junit.Test; -import org.sonar.api.batch.bootstrap.*; +import org.sonar.api.batch.bootstrap.ProjectReactor; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; - public class BatchTest { @Test public void testBuilder() { @@ -36,45 +35,44 @@ public class BatchTest { private Batch newBatch() { return Batch.builder() - .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) - .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) - .addComponent("fake") - .build(); + .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) + .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) + .addComponent("fake") + .build(); } @Test(expected = IllegalStateException.class) public void shouldFailIfNoEnvironment() { Batch.builder() - .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) - .addComponent("fake") - .build(); + .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) + .addComponent("fake") + .build(); } - @Test(expected = IllegalStateException.class) - public void shouldFailIfNoProjectReactor() { + public void shouldNotFailIfNoProjectReactor() { Batch.builder() - .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) - .addComponent("fake") - .build(); + .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) + .addComponent("fake") + .build(); } @Test(expected = IllegalStateException.class) public void shouldFailIfNullComponents() { Batch.builder() - .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) - .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) - .setComponents(null) - .build(); + .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) + .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) + .setComponents(null) + .build(); } @Test public void shouldDisableLoggingConfiguration() { Batch batch = Batch.builder() - .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) - .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) - .addComponent("fake") - .setEnableLoggingConfiguration(false) - .build(); + .setEnvironment(new EnvironmentInformation("Gradle", "1.0")) + .setProjectReactor(new ProjectReactor(org.sonar.api.batch.bootstrap.ProjectDefinition.create())) + .addComponent("fake") + .setEnableLoggingConfiguration(false) + .build(); assertNull(batch.getLoggingConfiguration()); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/TaskDefinitionExtension.java b/sonar-plugin-api/src/main/java/org/sonar/api/TaskDefinitionExtension.java new file mode 100644 index 00000000000..a01ef69b509 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/TaskDefinitionExtension.java @@ -0,0 +1,28 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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; + +/** + * Task definition extension point. + * + * @since 3.5 + */ +public interface TaskDefinitionExtension extends Extension { +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/TaskExtension.java b/sonar-plugin-api/src/main/java/org/sonar/api/TaskExtension.java new file mode 100644 index 00000000000..147d7237d5e --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/TaskExtension.java @@ -0,0 +1,28 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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; + +/** + * Task extension point. + * + * @since 3.5 + */ +public interface TaskExtension extends Extension { +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskDefinition.java new file mode 100644 index 00000000000..e442a60d45f --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskDefinition.java @@ -0,0 +1,34 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.batch; + +import org.sonar.api.TaskDefinitionExtension; + +/** + * Implement this interface to provide a new task. + * @since 3.5 + */ +public interface TaskDefinition extends TaskDefinitionExtension { + + TaskDescriptor getTaskDescriptor(); + + Class<? extends TaskExecutor> getExecutor(); + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskDescriptor.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskDescriptor.java new file mode 100644 index 00000000000..78cda168eda --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskDescriptor.java @@ -0,0 +1,77 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.batch; + +/** + * Provide description of a task. + * @since 3.5 + */ +public class TaskDescriptor { + + private String name; + private String decription; + private String command; + private boolean requiresProject = false; + + private TaskDescriptor() { + + } + + public static TaskDescriptor create() { + return new TaskDescriptor(); + } + + public String getName() { + return name; + } + + public TaskDescriptor setName(String name) { + this.name = name; + return this; + } + + public String getDecription() { + return decription; + } + + public TaskDescriptor setDescription(String decription) { + this.decription = decription; + return this; + } + + public String getCommand() { + return command; + } + + public TaskDescriptor setCommand(String command) { + this.command = command; + return this; + } + + public boolean isRequiresProject() { + return requiresProject; + } + + public TaskDescriptor setRequiresProject(boolean requiresProject) { + this.requiresProject = requiresProject; + return this; + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskExecutor.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskExecutor.java new file mode 100644 index 00000000000..cb6998b92f7 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/TaskExecutor.java @@ -0,0 +1,32 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * 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.batch; + +import org.sonar.api.TaskExtension; + +/** + * Implement this interface to provide the behavior of a task. + * @since 3.5 + */ +public interface TaskExecutor extends TaskExtension { + + void execute(); + +} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb index 45fd241e2f4..ebc5a53524f 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb @@ -32,8 +32,6 @@ class BatchBootstrapController < Api::ApiController # GET /batch_bootstrap/properties?project=<key or id> def properties - require_parameters :project - json_properties=Property.find(:all, :conditions => ['user_id is null and resource_id is null']).map { |property| to_json_property(property) } root_project = load_project() @@ -71,4 +69,4 @@ class BatchBootstrapController < Api::ApiController true end end -end
\ No newline at end of file +end |