@@ -22,56 +22,38 @@ package org.sonar.batch; | |||
import org.apache.commons.configuration.Configuration; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.bootstrap.BootstrapContainer; | |||
import org.sonar.batch.bootstrap.Container; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.batch.bootstrapper.Reactor; | |||
import java.util.Iterator; | |||
import java.util.Properties; | |||
/** | |||
* @deprecated Replaced by {@link org.sonar.batch.bootstrapper.Batch} since version 2.14. | |||
* @deprecated in 2.14. Replaced by {@link org.sonar.batch.bootstrapper.Batch}. | |||
*/ | |||
@Deprecated | |||
public final class Batch { | |||
private Container bootstrapModule; | |||
private Object[] bootstrapExtensions; | |||
private ProjectReactor reactor; | |||
public Batch(ProjectReactor reactor, Object... bootstrapperComponents) { | |||
this.bootstrapModule = new BootstrapContainer(reactor, bootstrapperComponents); | |||
this.bootstrapModule.init(); | |||
this.reactor = reactor; | |||
this.bootstrapExtensions = bootstrapperComponents; | |||
} | |||
/** | |||
* @deprecated since 2.9 because commons-configuration is replaced by ProjectDefinition#properties. Used by Ant Task 1.1 | |||
*/ | |||
@Deprecated | |||
public Batch(Configuration configuration, Object... bootstrapperComponents) {//NOSONAR configuration is not needed | |||
public Batch(Configuration configuration, Object... bootstrapperComponents) { | |||
// configuration is not needed | |||
// because it's already included in ProjectDefinition. | |||
this.bootstrapModule = new BootstrapContainer(extractProjectReactor(bootstrapperComponents), bootstrapperComponents); | |||
this.bootstrapModule.init(); | |||
} | |||
static ProjectReactor extractProjectReactor(Object[] components) { | |||
Reactor deprecatedReactor = null; | |||
for (Object component : components) { | |||
if (component instanceof ProjectReactor) { | |||
return (ProjectReactor) component; | |||
} | |||
if (component instanceof Reactor) { | |||
deprecatedReactor = (Reactor) component; | |||
} | |||
} | |||
if (deprecatedReactor == null) { | |||
throw new IllegalArgumentException("Project reactor is not defined"); | |||
} | |||
return deprecatedReactor.toProjectReactor(); | |||
this.bootstrapExtensions = bootstrapperComponents; | |||
this.reactor = extractProjectReactor(bootstrapperComponents); | |||
} | |||
/** | |||
* Used by Gradle 1.0 | |||
* | |||
* @deprecated in version 2.12 | |||
*/ | |||
@Deprecated | |||
@@ -94,18 +76,27 @@ public final class Batch { | |||
return props; | |||
} | |||
/** | |||
* for unit tests | |||
*/ | |||
Batch(Container bootstrapModule) { | |||
this.bootstrapModule = bootstrapModule; | |||
static ProjectReactor extractProjectReactor(Object[] components) { | |||
Reactor deprecatedReactor = null; | |||
for (Object component : components) { | |||
if (component instanceof ProjectReactor) { | |||
return (ProjectReactor) component; | |||
} | |||
if (component instanceof Reactor) { | |||
deprecatedReactor = (Reactor) component; | |||
} | |||
} | |||
if (deprecatedReactor == null) { | |||
throw new IllegalArgumentException("Project reactor is not defined"); | |||
} | |||
return deprecatedReactor.toProjectReactor(); | |||
} | |||
public void execute() { | |||
try { | |||
bootstrapModule.start(); | |||
} finally { | |||
bootstrapModule.stop(); | |||
} | |||
org.sonar.batch.bootstrapper.Batch.Builder builder = org.sonar.batch.bootstrapper.Batch.builder(); | |||
builder.setProjectReactor(reactor); | |||
builder.addComponents(bootstrapExtensions); | |||
builder.build().execute(); | |||
} | |||
} |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.Maps; | |||
import org.apache.commons.configuration.Configuration; | |||
import org.apache.commons.lang.StringUtils; | |||
@@ -43,39 +42,34 @@ public class BatchSettings extends Settings { | |||
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); | |||
ServerClient client, Configuration deprecatedConfiguration, BootstrapProperties globalProperties) { | |||
this(bootstrapSettings, propertyDefinitions, client, deprecatedConfiguration, globalProperties, null); | |||
} | |||
public BatchSettings(BootstrapSettings bootstrapSettings, PropertyDefinitions propertyDefinitions, @Nullable ProjectReactor reactor, | |||
ServerClient client, Configuration deprecatedConfiguration, GlobalBatchProperties globalProperties) { | |||
public BatchSettings(BootstrapSettings bootstrapSettings, PropertyDefinitions propertyDefinitions, | |||
ServerClient client, Configuration deprecatedConfiguration, BootstrapProperties bootstrapProperties, | |||
@Nullable ProjectReactor projectReactor) { | |||
super(propertyDefinitions); | |||
this.deprecatedConfiguration = deprecatedConfiguration; | |||
init(bootstrapSettings, reactor, client, globalProperties); | |||
} | |||
@VisibleForTesting | |||
public BatchSettings() { | |||
init(bootstrapSettings, client, bootstrapProperties, projectReactor); | |||
} | |||
private void init(BootstrapSettings bootstrapSettings, @Nullable ProjectReactor reactor, ServerClient client, | |||
GlobalBatchProperties globalProperties) { | |||
private void init(BootstrapSettings bootstrapSettings, ServerClient client, BootstrapProperties bootstrapProperties, @Nullable ProjectReactor reactor) { | |||
LoggerFactory.getLogger(BatchSettings.class).info("Load batch settings"); | |||
if (reactor != null) { | |||
String branch = bootstrapSettings.getProperty(CoreProperties.PROJECT_BRANCH_PROPERTY); | |||
String branch = bootstrapSettings.property(CoreProperties.PROJECT_BRANCH_PROPERTY); | |||
String projectKey = reactor.getRoot().getKey(); | |||
if (StringUtils.isNotBlank(branch)) { | |||
projectKey = String.format("%s:%s", projectKey, branch); | |||
} | |||
downloadSettings(client, projectKey); | |||
} | |||
else { | |||
} else { | |||
downloadSettings(client, null); | |||
} | |||
// order is important -> bottom-up. The last one overrides all the others. | |||
addProperties(globalProperties.getProperties()); | |||
addProperties(bootstrapProperties.properties()); | |||
if (reactor != null) { | |||
addProperties(reactor.getRoot().getProperties()); | |||
} | |||
@@ -87,8 +81,7 @@ public class BatchSettings extends Settings { | |||
String url; | |||
if (StringUtils.isNotBlank(projectKey)) { | |||
url = "/batch_bootstrap/properties?project=" + projectKey; | |||
} | |||
else { | |||
} else { | |||
url = "/batch_bootstrap/properties"; | |||
} | |||
String jsonText = client.request(url); | |||
@@ -97,7 +90,7 @@ public class BatchSettings extends Settings { | |||
String key = jsonProperty.get("k"); | |||
String value = jsonProperty.get("v"); | |||
String moduleKey = jsonProperty.get("p"); | |||
if (moduleKey == null || projectKey.equals(moduleKey)) { | |||
if (moduleKey == null || projectKey == null || moduleKey.equals(projectKey)) { | |||
setProperty(key, value); | |||
} | |||
if (moduleKey != null) { |
@@ -20,91 +20,131 @@ | |||
package org.sonar.batch.bootstrap; | |||
import org.apache.commons.configuration.PropertiesConfiguration; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.api.config.EmailSettings; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.platform.PluginMetadata; | |||
import org.sonar.api.utils.HttpDownloader; | |||
import org.sonar.api.utils.UriReader; | |||
import org.sonar.batch.scan.maven.FakeMavenPluginExecutor; | |||
import org.sonar.batch.scan.maven.MavenPluginExecutor; | |||
import org.sonar.batch.components.PastMeasuresLoader; | |||
import org.sonar.batch.components.PastSnapshotFinder; | |||
import org.sonar.batch.components.PastSnapshotFinderByDate; | |||
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.core.config.Logback; | |||
import org.sonar.core.i18n.I18nManager; | |||
import org.sonar.core.i18n.RuleI18nManager; | |||
import org.sonar.core.metric.CacheMetricFinder; | |||
import org.sonar.core.persistence.DaoUtils; | |||
import org.sonar.core.persistence.DatabaseVersion; | |||
import org.sonar.core.persistence.MyBatis; | |||
import org.sonar.core.persistence.SemaphoreUpdater; | |||
import org.sonar.core.persistence.SemaphoresImpl; | |||
import org.sonar.core.qualitymodel.DefaultModelFinder; | |||
import org.sonar.core.rule.CacheRuleFinder; | |||
import org.sonar.core.user.DefaultUserFinder; | |||
import org.sonar.jpa.dao.MeasuresDao; | |||
import org.sonar.jpa.dao.ProfilesDao; | |||
import org.sonar.jpa.dao.RulesDao; | |||
import org.sonar.jpa.session.DefaultDatabaseConnector; | |||
import org.sonar.jpa.session.JpaDatabaseSession; | |||
import javax.annotation.Nullable; | |||
import java.util.List; | |||
import java.util.Map; | |||
/** | |||
* Level 1 components | |||
*/ | |||
public class BootstrapContainer extends Container { | |||
public class BootstrapContainer extends ComponentContainer { | |||
private Object[] boostrapperComponents; | |||
private ProjectReactor reactor; | |||
private GlobalBatchProperties globalProperties; | |||
private String taskCommand; | |||
private BootstrapContainer() { | |||
super(); | |||
} | |||
/** | |||
* @deprecated Use {@link #BootstrapModule(GlobalBatchProperties, String, ProjectReactor, Object...)} | |||
*/ | |||
@Deprecated | |||
public BootstrapContainer(ProjectReactor reactor, Object... boostrapperComponents) { | |||
this(new GlobalBatchProperties(), null, reactor, boostrapperComponents); | |||
@Override | |||
protected void doBeforeStart() { | |||
addBootstrapComponents(); | |||
addDatabaseComponents(); | |||
addCoreComponents(); | |||
} | |||
public BootstrapContainer(GlobalBatchProperties globalProperties, @Nullable String taskCommand, @Nullable ProjectReactor reactor, | |||
Object... boostrapperComponents) { | |||
this.globalProperties = globalProperties; | |||
this.taskCommand = taskCommand; | |||
this.reactor = reactor; | |||
this.boostrapperComponents = boostrapperComponents; | |||
private void addBootstrapComponents() { | |||
add( | |||
new PropertiesConfiguration(), | |||
BootstrapSettings.class, | |||
PluginDownloader.class, | |||
BatchPluginRepository.class, | |||
BatchSettings.class, | |||
ServerClient.class, | |||
ExtensionInstaller.class, | |||
Logback.class, | |||
ServerMetadata.class, | |||
org.sonar.batch.ServerMetadata.class, | |||
TempDirectories.class, | |||
HttpDownloader.class, | |||
UriReader.class, | |||
new FileCacheProvider() | |||
); | |||
} | |||
@Override | |||
protected void configure() { | |||
container.addSingleton(globalProperties); | |||
if (reactor != null) { | |||
container.addSingleton(reactor); | |||
} | |||
container.addSingleton(new PropertiesConfiguration()); | |||
container.addSingleton(BootstrapSettings.class); | |||
container.addSingleton(ServerClient.class); | |||
container.addSingleton(BatchSettings.class); | |||
container.addSingleton(BatchPluginRepository.class); | |||
container.addSingleton(ExtensionInstaller.class); | |||
container.addSingleton(Logback.class); | |||
container.addSingleton(ServerMetadata.class); | |||
container.addSingleton(org.sonar.batch.ServerMetadata.class); | |||
container.addSingleton(TempDirectories.class); | |||
container.addSingleton(HttpDownloader.class); | |||
container.addSingleton(UriReader.class); | |||
container.addSingleton(PluginDownloader.class); | |||
container.addPicoAdapter(new FileCacheProvider()); | |||
for (Object component : boostrapperComponents) { | |||
if (component != null) { | |||
container.addSingleton(component); | |||
} | |||
} | |||
if (!isMavenPluginExecutorRegistered()) { | |||
container.addSingleton(FakeMavenPluginExecutor.class); | |||
} | |||
private void addDatabaseComponents() { | |||
add( | |||
DryRunDatabase.class, | |||
JdbcDriverHolder.class, | |||
BatchDatabase.class, | |||
MyBatis.class, | |||
DatabaseVersion.class, | |||
//TODO check that it still works (see @Freddy) | |||
DatabaseCompatibility.class, | |||
DefaultDatabaseConnector.class, | |||
JpaDatabaseSession.class, | |||
BatchDatabaseSessionFactory.class, | |||
DaoUtils.getDaoClasses() | |||
); | |||
} | |||
boolean isMavenPluginExecutorRegistered() { | |||
if (boostrapperComponents != null) { | |||
for (Object component : boostrapperComponents) { | |||
if (component instanceof Class && MavenPluginExecutor.class.isAssignableFrom((Class<?>) component)) { | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
/** | |||
* These components MUST not depend on extensions provided by plugins | |||
*/ | |||
private void addCoreComponents() { | |||
add( | |||
EmailSettings.class, | |||
I18nManager.class, | |||
RuleI18nManager.class, | |||
MeasuresDao.class, | |||
RulesDao.class, | |||
ProfilesDao.class, | |||
CacheRuleFinder.class, | |||
CacheMetricFinder.class, | |||
DefaultUserFinder.class, | |||
SemaphoreUpdater.class, | |||
SemaphoresImpl.class, | |||
PastSnapshotFinderByDate.class, | |||
PastSnapshotFinderByDays.class, | |||
PastSnapshotFinderByPreviousAnalysis.class, | |||
PastSnapshotFinderByVersion.class, | |||
PastSnapshotFinderByPreviousVersion.class, | |||
PastMeasuresLoader.class, | |||
PastSnapshotFinder.class, | |||
DefaultModelFinder.class | |||
); | |||
} | |||
@Override | |||
protected void doStart() { | |||
Container childModule = new TaskBootstrapContainer(taskCommand); | |||
try { | |||
installChild(childModule); | |||
childModule.start(); | |||
} finally { | |||
childModule.stop(); | |||
uninstallChild(); | |||
protected void doAfterStart() { | |||
installPlugins(); | |||
} | |||
private void installPlugins() { | |||
for (Map.Entry<PluginMetadata, Plugin> entry : get(BatchPluginRepository.class).getPluginsByMetadata().entrySet()) { | |||
PluginMetadata metadata = entry.getKey(); | |||
Plugin plugin = entry.getValue(); | |||
addExtension(metadata, plugin); | |||
} | |||
} | |||
public static BootstrapContainer create(List objects) { | |||
BootstrapContainer container = new BootstrapContainer(); | |||
container.add(objects); | |||
return container; | |||
} | |||
} |
@@ -19,29 +19,23 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.collect.Maps; | |||
import com.google.common.collect.ImmutableMap; | |||
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 class BootstrapProperties { | |||
public GlobalBatchProperties() { | |||
this.properties = Maps.newHashMap(); | |||
} | |||
private final Map<String, String> properties; | |||
public GlobalBatchProperties(Map<String, String> properties) { | |||
this.properties = Maps.newHashMap(properties); | |||
public BootstrapProperties(Map<String, String> properties) { | |||
this.properties = ImmutableMap.copyOf(properties); | |||
} | |||
public Map<String, String> getProperties() { | |||
Map<String, String> properties() { | |||
return properties; | |||
} | |||
@@ -23,6 +23,8 @@ import com.google.common.collect.Maps; | |||
import org.codehaus.plexus.util.StringUtils; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import javax.annotation.Nullable; | |||
import java.util.Map; | |||
import java.util.Properties; | |||
@@ -32,21 +34,17 @@ import java.util.Properties; | |||
public class BootstrapSettings { | |||
private Map<String, String> properties; | |||
public BootstrapSettings(GlobalBatchProperties globalProperties) { | |||
init(null, globalProperties); | |||
} | |||
public BootstrapSettings(ProjectReactor reactor, GlobalBatchProperties globalProperties) { | |||
init(reactor, globalProperties); | |||
public BootstrapSettings(BootstrapProperties bootstrapProperties) { | |||
this(bootstrapProperties, null); | |||
} | |||
private void init(ProjectReactor reactor, GlobalBatchProperties globalProperties) { | |||
public BootstrapSettings(BootstrapProperties bootstrapProperties, @Nullable ProjectReactor projectReactor) { | |||
properties = Maps.newHashMap(); | |||
// order is important -> bottom-up. The last one overrides all the others. | |||
properties.putAll(globalProperties.getProperties()); | |||
if (reactor != null) { | |||
addProperties(reactor.getRoot().getProperties()); | |||
properties.putAll(bootstrapProperties.properties()); | |||
if (projectReactor != null) { | |||
addProperties(projectReactor.getRoot().getProperties()); | |||
} | |||
properties.putAll(System.getenv()); | |||
addProperties(System.getProperties()); | |||
@@ -60,15 +58,15 @@ public class BootstrapSettings { | |||
} | |||
} | |||
public Map<String, String> getProperties() { | |||
public Map<String, String> properties() { | |||
return properties; | |||
} | |||
public String getProperty(String key) { | |||
public String property(String key) { | |||
return properties.get(key); | |||
} | |||
public String getProperty(String key, String defaultValue) { | |||
public String property(String key, String defaultValue) { | |||
return StringUtils.defaultString(properties.get(key), defaultValue); | |||
} | |||
} |
@@ -31,6 +31,8 @@ import org.sonar.api.config.Settings; | |||
import org.sonar.api.database.DatabaseProperties; | |||
import org.sonar.api.utils.SonarException; | |||
import javax.annotation.Nullable; | |||
import java.io.File; | |||
import static org.sonar.api.utils.HttpDownloader.HttpException; | |||
@@ -50,22 +52,25 @@ public class DryRunDatabase implements BatchComponent { | |||
private final Settings settings; | |||
private final ServerClient server; | |||
private final TempDirectories tempDirectories; | |||
private final ProjectReactor reactor; | |||
private ProjectReactor reactor; | |||
public DryRunDatabase(Settings settings, ServerClient server, TempDirectories tempDirectories, ProjectReactor reactor, | |||
// project reactor must be completely built | |||
ProjectReactorReady reactorReady) { | |||
public DryRunDatabase(Settings settings, ServerClient server, TempDirectories tempDirectories, @Nullable ProjectReactor reactor) { | |||
this.settings = settings; | |||
this.server = server; | |||
this.tempDirectories = tempDirectories; | |||
this.reactor = reactor; | |||
} | |||
public DryRunDatabase(Settings settings, ServerClient server, TempDirectories tempDirectories) { | |||
this(settings, server, tempDirectories, null); | |||
} | |||
public void start() { | |||
if (settings.getBoolean(CoreProperties.DRY_RUN)) { | |||
LOG.info("Dry run"); | |||
File databaseFile = tempDirectories.getFile("", "dryrun.h2.db"); | |||
downloadDatabase(reactor.getRoot().getKey(), databaseFile); | |||
String projectKey = reactor != null ? StringUtils.defaultString(reactor.getRoot().getKey()) : ""; | |||
downloadDatabase(projectKey, databaseFile); | |||
String databasePath = StringUtils.removeEnd(databaseFile.getAbsolutePath(), ".h2.db"); | |||
replaceSettings(databasePath); |
@@ -19,19 +19,12 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.BatchComponent; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.ExtensionProvider; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.platform.PluginMetadata; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.api.task.TaskDefinition; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import javax.annotation.Nullable; | |||
@@ -39,167 +32,58 @@ import javax.annotation.Nullable; | |||
import java.util.List; | |||
import java.util.Map; | |||
public class ExtensionInstaller implements BatchComponent { | |||
// TODO rename ExtensionInstaller | |||
public class ExtensionInstaller { | |||
private static final Logger LOG = LoggerFactory.getLogger(ExtensionInstaller.class); | |||
private final BatchPluginRepository pluginRepository; | |||
private final EnvironmentInformation env; | |||
private final Settings settings; | |||
private BatchPluginRepository pluginRepository; | |||
private EnvironmentInformation environment; | |||
private Settings settings; | |||
public ExtensionInstaller(BatchPluginRepository pluginRepository, EnvironmentInformation environment, Settings settings) { | |||
public ExtensionInstaller(BatchPluginRepository pluginRepository, EnvironmentInformation env, Settings settings) { | |||
this.pluginRepository = pluginRepository; | |||
this.environment = environment; | |||
this.env = env; | |||
this.settings = settings; | |||
} | |||
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); | |||
} | |||
} | |||
} | |||
boolean installTaskDefinition(ComponentContainer container, @Nullable PluginMetadata plugin, Object extension) { | |||
boolean installed; | |||
if (ExtensionUtils.isType(extension, TaskDefinition.class) | |||
&& ExtensionUtils.supportsEnvironment(extension, environment)) { | |||
LOG.debug("Installing task definition extension {} from plugin {}", extension.toString(), plugin.getKey()); | |||
container.addExtension(plugin, extension); | |||
installed = true; | |||
} else { | |||
container.declareExtension(plugin, extension); | |||
installed = false; | |||
} | |||
return installed; | |||
} | |||
public void installTaskExtensions(ComponentContainer container, boolean projectPresent) { | |||
boolean dryRun = settings.getBoolean(CoreProperties.DRY_RUN); | |||
public ExtensionInstaller install(ComponentContainer container, ComponentFilter matcher) { | |||
boolean dryRun = isDryRun(); | |||
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, projectPresent); | |||
if (projectPresent) { | |||
installBatchExtension(container, metadata, extension, dryRun, InstantiationStrategy.PER_BATCH); | |||
} | |||
doInstall(container, matcher, metadata, dryRun, extension); | |||
} | |||
} | |||
List<ExtensionProvider> providers = container.getComponentsByType(ExtensionProvider.class); | |||
for (ExtensionProvider provider : providers) { | |||
executeTaskExtensionProvider(container, provider, projectPresent); | |||
if (projectPresent) { | |||
executeBatchExtensionProvider(container, InstantiationStrategy.PER_BATCH, dryRun, provider); | |||
} | |||
} | |||
} | |||
private void executeTaskExtensionProvider(ComponentContainer container, ExtensionProvider provider, boolean projectPresent) { | |||
Object obj = provider.provide(); | |||
if (obj instanceof Iterable) { | |||
for (Object extension : (Iterable) obj) { | |||
installTaskExtension(container, null, extension, projectPresent); | |||
} | |||
} else { | |||
installTaskExtension(container, null, obj, projectPresent); | |||
} | |||
} | |||
boolean installTaskExtension(ComponentContainer container, @Nullable PluginMetadata plugin, Object extension, boolean projectPresent) { | |||
boolean installed; | |||
if (ExtensionUtils.isTaskExtension(extension) && | |||
(projectPresent || !ExtensionUtils.requiresProject(extension)) && | |||
ExtensionUtils.supportsEnvironment(extension, environment)) { | |||
logInstallExtension("task", plugin, extension); | |||
container.addExtension(plugin, extension); | |||
installed = true; | |||
} else { | |||
container.declareExtension(plugin, extension); | |||
installed = false; | |||
} | |||
return installed; | |||
} | |||
public void installInspectionExtensions(ComponentContainer container) { | |||
installBatchExtensions(container, InstantiationStrategy.PER_PROJECT); | |||
} | |||
@VisibleForTesting | |||
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(); | |||
Plugin plugin = entry.getValue(); | |||
container.addExtension(metadata, plugin); | |||
for (Object extension : plugin.getExtensions()) { | |||
installBatchExtension(container, metadata, extension, dryRun, instantiationStrategy); | |||
} | |||
} | |||
List<ExtensionProvider> providers = container.getComponentsByType(ExtensionProvider.class); | |||
for (ExtensionProvider provider : providers) { | |||
executeBatchExtensionProvider(container, instantiationStrategy, dryRun, 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) { | |||
installBatchExtension(container, null, extension, dryRun, instantiationStrategy); | |||
Object object = provider.provide(); | |||
if (object instanceof Iterable) { | |||
for (Object extension : (Iterable) object) { | |||
doInstall(container, matcher, null, dryRun, extension); | |||
} | |||
} else { | |||
doInstall(container, matcher, null, dryRun, object); | |||
} | |||
} else { | |||
installBatchExtension(container, null, obj, dryRun, instantiationStrategy); | |||
} | |||
return this; | |||
} | |||
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)) { | |||
logInstallExtension("batch", plugin, extension); | |||
container.addExtension(plugin, extension); | |||
installed = true; | |||
private void doInstall(ComponentContainer container, ComponentFilter matcher, @Nullable PluginMetadata metadata, boolean dryRun, Object extension) { | |||
if (ExtensionUtils.supportsEnvironment(extension, env) | |||
&& (!dryRun || ExtensionUtils.supportsDryRun(extension)) | |||
&& matcher.accept(extension)) { | |||
container.addExtension(metadata, extension); | |||
} else { | |||
container.declareExtension(plugin, extension); | |||
installed = false; | |||
container.declareExtension(metadata, extension); | |||
} | |||
return installed; | |||
} | |||
/** | |||
* Special use-case: the extension point ProjectBuilder is used in a Maven environment to define some | |||
* new sub-projects without pom. | |||
* Example : C# plugin adds sub-projects at runtime, even if they are not defined in root pom. | |||
*/ | |||
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 false; | |||
private boolean isDryRun() { | |||
return settings.getBoolean(CoreProperties.DRY_RUN); | |||
} | |||
private void logInstallExtension(String extensionType, PluginMetadata plugin, Object extension) { | |||
if (plugin != null) { | |||
LOG.debug("Installing {} extension {} from plugin {}", new String[] {extensionType, extension.toString(), plugin.getKey()}); | |||
} | |||
else { | |||
LOG.debug("Installing {} extension {}", extensionType, extension.toString()); | |||
} | |||
// TODO rename ExtensionMatcher | |||
public interface ComponentFilter { | |||
boolean accept(Object extension); | |||
} | |||
} |
@@ -23,19 +23,17 @@ import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.batch.SupportedEnvironment; | |||
import org.sonar.api.task.TaskExtension; | |||
import org.sonar.api.utils.AnnotationUtils; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.batch.tasks.RequiresProject; | |||
import org.sonar.core.DryRunIncompatible; | |||
final class ExtensionUtils { | |||
public class ExtensionUtils { | |||
private ExtensionUtils() { | |||
// only static methods | |||
} | |||
static boolean isInstantiationStrategy(Object extension, String strategy) { | |||
public static boolean isInstantiationStrategy(Object extension, String strategy) { | |||
InstantiationStrategy annotation = AnnotationUtils.getAnnotation(extension, InstantiationStrategy.class); | |||
if (annotation != null) { | |||
return strategy.equals(annotation.value()); | |||
@@ -43,15 +41,11 @@ final class ExtensionUtils { | |||
return InstantiationStrategy.PER_PROJECT.equals(strategy); | |||
} | |||
static boolean isTaskExtension(Object extension) { | |||
return isType(extension, TaskExtension.class); | |||
} | |||
static boolean isBatchExtension(Object extension) { | |||
public static boolean isBatchExtension(Object extension) { | |||
return isType(extension, BatchExtension.class); | |||
} | |||
static boolean supportsEnvironment(Object extension, EnvironmentInformation environment) { | |||
public static boolean supportsEnvironment(Object extension, EnvironmentInformation environment) { | |||
SupportedEnvironment env = AnnotationUtils.getAnnotation(extension, SupportedEnvironment.class); | |||
if (env == null) { | |||
return true; | |||
@@ -64,20 +58,16 @@ final class ExtensionUtils { | |||
return false; | |||
} | |||
static boolean supportsDryRun(Object extension) { | |||
public static boolean supportsDryRun(Object extension) { | |||
return AnnotationUtils.getAnnotation(extension, DryRunIncompatible.class) == null; | |||
} | |||
static boolean requiresProject(Object extension) { | |||
return AnnotationUtils.getAnnotation(extension, RequiresProject.class) != null; | |||
} | |||
static boolean isMavenExtensionOnly(Object extension) { | |||
public 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]); | |||
} | |||
static boolean isType(Object extension, Class<?> extensionClass) { | |||
public static boolean isType(Object extension, Class<?> extensionClass) { | |||
Class clazz = (extension instanceof Class ? (Class) extension : extension.getClass()); | |||
return extensionClass.isAssignableFrom(clazz); | |||
} |
@@ -20,18 +20,15 @@ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.collect.Lists; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.ExtensionProvider; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.measures.Metrics; | |||
import org.sonar.api.task.TaskComponent; | |||
import java.util.List; | |||
@InstantiationStrategy(InstantiationStrategy.PER_BATCH) | |||
public class MetricProvider extends ExtensionProvider implements BatchExtension { | |||
public class MetricProvider extends ExtensionProvider implements TaskComponent { | |||
private Metrics[] factories; | |||
@@ -45,7 +42,6 @@ public class MetricProvider extends ExtensionProvider implements BatchExtension | |||
@Override | |||
public List<Metric> provide() { | |||
LoggerFactory.getLogger(MetricProvider.class).debug("Load metrics"); | |||
List<Metric> metrics = Lists.newArrayList(CoreMetrics.getMetrics()); | |||
for (Metrics factory : factories) { | |||
metrics.addAll(factory.getMetrics()); |
@@ -38,6 +38,7 @@ import java.io.InputStream; | |||
import java.net.URI; | |||
/** | |||
* Replace the deprecated org.sonar.batch.ServerMetadata | |||
* TODO extends Server when removing the deprecated org.sonar.batch.ServerMetadata | |||
* | |||
* @since 3.4 | |||
@@ -48,11 +49,11 @@ public class ServerClient implements BatchComponent { | |||
public ServerClient(BootstrapSettings settings, EnvironmentInformation env) { | |||
this.settings = settings; | |||
this.downloader = new HttpDownloader.BaseHttpDownloader(settings.getProperties(), env.toString()); | |||
this.downloader = new HttpDownloader.BaseHttpDownloader(settings.properties(), env.toString()); | |||
} | |||
public String getURL() { | |||
return StringUtils.removeEnd(settings.getProperty("sonar.host.url", "http://localhost:9000"), "/"); | |||
return StringUtils.removeEnd(settings.property("sonar.host.url", "http://localhost:9000"), "/"); | |||
} | |||
public void download(String pathStartingWithSlash, File toFile) { | |||
@@ -86,14 +87,14 @@ public class ServerClient implements BatchComponent { | |||
String path = StringEscapeUtils.escapeHtml(pathStartingWithSlash); | |||
URI uri = URI.create(getURL() + path); | |||
String login = settings.getProperty(CoreProperties.LOGIN); | |||
String login = settings.property(CoreProperties.LOGIN); | |||
try { | |||
InputSupplier<InputStream> inputSupplier; | |||
if (Strings.isNullOrEmpty(login)) { | |||
inputSupplier = downloader.newInputSupplier(uri); | |||
} else { | |||
inputSupplier = downloader.newInputSupplier(uri, login, settings.getProperty(CoreProperties.PASSWORD)); | |||
inputSupplier = downloader.newInputSupplier(uri, login, settings.property(CoreProperties.PASSWORD)); | |||
} | |||
return inputSupplier; | |||
} catch (Exception e) { | |||
@@ -109,8 +110,8 @@ public class ServerClient implements BatchComponent { | |||
} | |||
private String getMessageWhenNotAuthorized() { | |||
String login = settings.getProperty(CoreProperties.LOGIN); | |||
String password = settings.getProperty(CoreProperties.PASSWORD); | |||
String login = settings.property(CoreProperties.LOGIN); | |||
String password = settings.property(CoreProperties.PASSWORD); | |||
if (StringUtils.isEmpty(login) && StringUtils.isEmpty(password)) { | |||
return "Not authorized. Analyzing this project requires to be authenticated. Please provide the values of the properties %s and %s."; | |||
} |
@@ -32,8 +32,9 @@ import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
/** | |||
* @since 3.4. Replaces the deprecated org.sonar.batch.ServerMetadata | |||
* @deprecated in 3.4. Replaced by {@link org.sonar.batch.bootstrap.ServerClient} | |||
*/ | |||
@Deprecated | |||
public class ServerMetadata extends Server implements BatchComponent { | |||
private Settings settings; |
@@ -1,79 +0,0 @@ | |||
/* | |||
* 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.bootstrap.ProjectReactor; | |||
import org.sonar.api.task.TaskDefinition; | |||
import org.sonar.api.utils.SonarException; | |||
import org.sonar.batch.scan.ScanTask; | |||
import org.sonar.batch.tasks.ListTasksTask; | |||
import org.sonar.batch.tasks.Tasks; | |||
import javax.annotation.Nullable; | |||
/** | |||
* Level-2 components. Collect tasks definitions. | |||
*/ | |||
public class TaskBootstrapContainer extends Container { | |||
private String taskCommand; | |||
public TaskBootstrapContainer(@Nullable String taskCommand) { | |||
this.taskCommand = taskCommand; | |||
} | |||
@Override | |||
protected void configure() { | |||
registerCoreTaskDefinitions(); | |||
registerTaskDefinitionExtensions(); | |||
container.addSingleton(Tasks.class); | |||
} | |||
private void registerCoreTaskDefinitions() { | |||
container.addSingleton(ScanTask.DEFINITION); | |||
container.addSingleton(ListTasksTask.DEFINITION); | |||
} | |||
private void registerTaskDefinitionExtensions() { | |||
ExtensionInstaller installer = container.getComponentByType(ExtensionInstaller.class); | |||
installer.installTaskDefinitionExtensions(container); | |||
} | |||
@Override | |||
protected void doStart() { | |||
Tasks tasks = container.getComponentByType(Tasks.class); | |||
executeTask(tasks.getTaskDefinition(taskCommand)); | |||
} | |||
private void executeTask(TaskDefinition taskDefinition) { | |||
boolean projectPresent = container.getComponentByType(ProjectReactor.class) != null; | |||
if (ExtensionUtils.requiresProject(taskDefinition.getTask()) && !projectPresent) { | |||
throw new SonarException("Task '" + taskDefinition.getName() + "' requires to be run on a project"); | |||
} | |||
Container childModule = new TaskContainer(taskDefinition, projectPresent); | |||
try { | |||
installChild(childModule); | |||
childModule.start(); | |||
} finally { | |||
childModule.stop(); | |||
uninstallChild(); | |||
} | |||
} | |||
} |
@@ -19,176 +19,54 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.config.EmailSettings; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.resources.ResourceTypes; | |||
import org.sonar.api.task.Task; | |||
import org.sonar.api.task.TaskDefinition; | |||
import org.sonar.api.task.TaskExtension; | |||
import org.sonar.api.utils.SonarException; | |||
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; | |||
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; | |||
import org.sonar.batch.index.EventPersister; | |||
import org.sonar.batch.index.LinkPersister; | |||
import org.sonar.batch.index.MeasurePersister; | |||
import org.sonar.batch.index.MemoryOptimizer; | |||
import org.sonar.batch.index.SourcePersister; | |||
import org.sonar.batch.scan.ScanTask; | |||
import org.sonar.batch.tasks.ListTasksTask; | |||
import org.sonar.core.component.ScanGraph; | |||
import org.sonar.core.component.ScanGraphStore; | |||
import org.sonar.core.component.ScanPerspectives; | |||
import org.sonar.core.i18n.I18nManager; | |||
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.DatabaseVersion; | |||
import org.sonar.core.persistence.MyBatis; | |||
import org.sonar.core.persistence.SemaphoreUpdater; | |||
import org.sonar.core.persistence.SemaphoresImpl; | |||
import org.sonar.core.resource.DefaultResourcePermissions; | |||
import org.sonar.core.rule.CacheRuleFinder; | |||
import org.sonar.core.test.TestPlanBuilder; | |||
import org.sonar.core.test.TestableBuilder; | |||
import org.sonar.core.user.DefaultUserFinder; | |||
import org.sonar.jpa.dao.MeasuresDao; | |||
import org.sonar.jpa.session.DefaultDatabaseConnector; | |||
import org.sonar.jpa.session.JpaDatabaseSession; | |||
import org.sonar.batch.tasks.Tasks; | |||
/** | |||
* Level-3 components. Task-level components that don't depends on project. | |||
*/ | |||
public class TaskContainer extends Container { | |||
private static final Logger LOG = LoggerFactory.getLogger(TaskContainer.class); | |||
import javax.annotation.Nullable; | |||
private TaskDefinition taskDefinition; | |||
private boolean projectPresent; | |||
public class TaskContainer extends ComponentContainer { | |||
public TaskContainer(TaskDefinition task, boolean projectPresent) { | |||
this.taskDefinition = task; | |||
this.projectPresent = projectPresent; | |||
public TaskContainer(ComponentContainer parent) { | |||
super(parent); | |||
} | |||
@Override | |||
protected void configure() { | |||
logSettings(); | |||
registerCoreComponents(); | |||
registerDatabaseComponents(); | |||
registerCoreTasks(); | |||
if (projectPresent) { | |||
registerCoreComponentsRequiringProject(); | |||
} | |||
registerTaskExtensions(); | |||
protected void doBeforeStart() { | |||
installTaskExtensions(); | |||
installComponentsUsingTaskExtensions(); | |||
} | |||
private void registerCoreComponents() { | |||
container.addSingleton(EmailSettings.class); | |||
container.addSingleton(I18nManager.class); | |||
container.addSingleton(RuleI18nManager.class); | |||
container.addSingleton(MeasuresDao.class); | |||
container.addSingleton(CacheRuleFinder.class); | |||
container.addSingleton(CacheMetricFinder.class); | |||
container.addSingleton(DefaultUserFinder.class); | |||
container.addSingleton(ResourceTypes.class); | |||
container.addSingleton(SemaphoreUpdater.class); | |||
container.addSingleton(SemaphoresImpl.class); | |||
container.addSingleton(PastSnapshotFinderByDate.class); | |||
container.addSingleton(PastSnapshotFinderByDays.class); | |||
container.addSingleton(PastSnapshotFinderByPreviousAnalysis.class); | |||
container.addSingleton(PastSnapshotFinderByVersion.class); | |||
container.addSingleton(PastSnapshotFinderByPreviousVersion.class); | |||
container.addSingleton(PastMeasuresLoader.class); | |||
container.addSingleton(PastSnapshotFinder.class); | |||
} | |||
public void executeTask(@Nullable String key) { | |||
startComponents(); | |||
TaskDefinition taskDef = get(Tasks.class).getTaskDefinition(key); | |||
if (taskDef != null) { | |||
Task task = get(taskDef.getTask()); | |||
if (task != null) { | |||
task.execute(); | |||
} else { | |||
throw new IllegalStateException("Command " + key + " is badly defined."); | |||
} | |||
private void registerDatabaseComponents() { | |||
container.addSingleton(JdbcDriverHolder.class); | |||
container.addSingleton(BatchDatabase.class); | |||
container.addSingleton(MyBatis.class); | |||
container.addSingleton(DatabaseVersion.class); | |||
container.addSingleton(DatabaseCompatibility.class); | |||
for (Class daoClass : DaoUtils.getDaoClasses()) { | |||
container.addSingleton(daoClass); | |||
} else { | |||
throw new SonarException("Command " + key + " does not exist."); | |||
} | |||
// hibernate | |||
container.addSingleton(DefaultDatabaseConnector.class); | |||
container.addSingleton(JpaDatabaseSession.class); | |||
container.addSingleton(BatchDatabaseSessionFactory.class); | |||
} | |||
private void registerCoreTasks() { | |||
container.addSingleton(ListTasksTask.class); | |||
if (projectPresent) { | |||
container.addSingleton(ScanTask.class); | |||
} | |||
} | |||
private void registerTaskExtensions() { | |||
ExtensionInstaller installer = container.getComponentByType(ExtensionInstaller.class); | |||
installer.installTaskExtensions(container, projectPresent); | |||
private void installTaskExtensions() { | |||
get(ExtensionInstaller.class).install(this, new ExtensionInstaller.ComponentFilter() { | |||
public boolean accept(Object extension) { | |||
return ExtensionUtils.isType(extension, TaskExtension.class); | |||
} | |||
}); | |||
} | |||
private void registerCoreComponentsRequiringProject() { | |||
container.addSingleton(DefaultResourceCreationLock.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); | |||
container.addSingleton(SourcePersister.class); | |||
container.addSingleton(DefaultNotificationManager.class); | |||
container.addSingleton(MetricProvider.class); | |||
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); | |||
// graphs | |||
container.addSingleton(ScanGraph.create()); | |||
container.addSingleton(TestPlanBuilder.class); | |||
container.addSingleton(TestableBuilder.class); | |||
container.addSingleton(ScanPerspectives.class); | |||
container.addSingleton(ScanGraphStore.class); | |||
private void installComponentsUsingTaskExtensions() { | |||
add(ResourceTypes.class, MetricProvider.class, Tasks.class); | |||
} | |||
private void logSettings() { | |||
LOG.info("------------- Executing {}", taskDefinition.getName()); | |||
} | |||
/** | |||
* Execute task | |||
*/ | |||
@Override | |||
protected void doStart() { | |||
Task task = container.getComponentByType(taskDefinition.getTask()); | |||
if (task != null) { | |||
task.execute(); | |||
} else { | |||
throw new SonarException("Extension " + taskDefinition.getTask() + " was not found in declared extensions."); | |||
} | |||
} | |||
} |
@@ -24,8 +24,10 @@ import com.google.common.collect.Maps; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.bootstrap.BootstrapContainer; | |||
import org.sonar.batch.bootstrap.GlobalBatchProperties; | |||
import org.sonar.batch.bootstrap.Container; | |||
import org.sonar.batch.bootstrap.BootstrapProperties; | |||
import org.sonar.batch.bootstrap.TaskContainer; | |||
import org.sonar.batch.scan.ScanTask; | |||
import org.sonar.batch.tasks.ListTasksTask; | |||
import org.sonar.core.PicoUtils; | |||
import java.util.Collections; | |||
@@ -48,11 +50,12 @@ public final class Batch { | |||
private Batch(Builder builder) { | |||
components = Lists.newArrayList(); | |||
components.addAll(builder.components); | |||
components.add(builder.environment); | |||
if (builder.environment != null) { | |||
components.add(builder.environment); | |||
} | |||
if (builder.globalProperties != null) { | |||
globalProperties.putAll(builder.globalProperties); | |||
} | |||
else { | |||
} else { | |||
// For backward compatibility, previously all properties were set in root project | |||
globalProperties.putAll(Maps.fromProperties(builder.projectReactor.getRoot().getProperties())); | |||
} | |||
@@ -80,18 +83,29 @@ public final class Batch { | |||
} | |||
private void startBatch() { | |||
Container bootstrapModule = null; | |||
BootstrapContainer bootstrapModule = null; | |||
try { | |||
bootstrapModule = new BootstrapContainer(new GlobalBatchProperties(globalProperties), taskCommand, | |||
projectReactor, components.toArray(new Object[components.size()])); | |||
bootstrapModule.init(); | |||
bootstrapModule.start(); | |||
List all = Lists.newArrayList(components); | |||
all.add(new BootstrapProperties(globalProperties)); | |||
all.add(projectReactor); | |||
bootstrapModule = BootstrapContainer.create(all); | |||
bootstrapModule.startComponents(); | |||
TaskContainer taskContainer = new TaskContainer(bootstrapModule); | |||
taskContainer.add( | |||
ScanTask.DEFINITION, ScanTask.class, | |||
ListTasksTask.DEFINITION, ListTasksTask.class | |||
); | |||
taskContainer.executeTask(taskCommand); | |||
} catch (RuntimeException e) { | |||
PicoUtils.propagateStartupException(e); | |||
} finally { | |||
try { | |||
if (bootstrapModule != null) { | |||
bootstrapModule.stop(); | |||
bootstrapModule.stopComponents(); | |||
} | |||
} catch (Exception e) { | |||
// never throw exceptions in a finally block | |||
@@ -164,9 +178,6 @@ public final class Batch { | |||
} | |||
public Batch build() { | |||
if (environment == null) { | |||
throw new IllegalStateException("EnvironmentInfo is not set"); | |||
} | |||
if (components == null) { | |||
throw new IllegalStateException("Batch components are not set"); | |||
} |
@@ -89,11 +89,11 @@ public final class Phases { | |||
/** | |||
* Executed on each module | |||
*/ | |||
public void execute(Project project) { | |||
pi.execute(project); | |||
eventBus.fireEvent(new ProjectAnalysisEvent(project, true)); | |||
mavenPluginsConfigurator.execute(project); | |||
mavenPhaseExecutor.execute(project); | |||
public void execute(Project module) { | |||
pi.execute(module); | |||
eventBus.fireEvent(new ProjectAnalysisEvent(module, true)); | |||
mavenPluginsConfigurator.execute(module); | |||
mavenPhaseExecutor.execute(module); | |||
initializersExecutor.execute(); | |||
fsLogger.log(); | |||
@@ -103,7 +103,7 @@ public final class Phases { | |||
persistenceManager.dump(); | |||
persistenceManager.setDelayedMode(false); | |||
if (project.isRoot()) { | |||
if (module.isRoot()) { | |||
graphStorage.save(); | |||
if (updateStatusJob != null) { | |||
updateStatusJob.execute(); | |||
@@ -111,7 +111,7 @@ public final class Phases { | |||
postJobsExecutor.execute(sensorContext); | |||
} | |||
cleanMemory(); | |||
eventBus.fireEvent(new ProjectAnalysisEvent(project, false)); | |||
eventBus.fireEvent(new ProjectAnalysisEvent(module, false)); | |||
} | |||
private void cleanMemory() { |
@@ -0,0 +1,149 @@ | |||
/* | |||
* 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.scan; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.batch.BatchExtensionDictionnary; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.profiles.RulesProfile; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.api.scan.filesystem.FileExclusions; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.batch.DefaultProfileLoader; | |||
import org.sonar.batch.DefaultProjectClasspath; | |||
import org.sonar.batch.DefaultSensorContext; | |||
import org.sonar.batch.DefaultTimeMachine; | |||
import org.sonar.batch.ProfileProvider; | |||
import org.sonar.batch.ProjectTree; | |||
import org.sonar.batch.ResourceFilters; | |||
import org.sonar.batch.ViolationFilters; | |||
import org.sonar.batch.bootstrap.ExtensionInstaller; | |||
import org.sonar.batch.bootstrap.ExtensionUtils; | |||
import org.sonar.batch.bootstrap.ProjectSettings; | |||
import org.sonar.batch.bootstrap.UnsupportedProperties; | |||
import org.sonar.batch.components.TimeMachineConfiguration; | |||
import org.sonar.batch.events.EventBus; | |||
import org.sonar.batch.index.DefaultIndex; | |||
import org.sonar.batch.index.ResourcePersister; | |||
import org.sonar.batch.local.DryRunExporter; | |||
import org.sonar.batch.phases.Phases; | |||
import org.sonar.batch.phases.PhasesTimeProfiler; | |||
import org.sonar.batch.scan.filesystem.DeprecatedFileSystemAdapter; | |||
import org.sonar.batch.scan.filesystem.ExclusionFilters; | |||
import org.sonar.batch.scan.filesystem.FileSystemLogger; | |||
import org.sonar.batch.scan.filesystem.LanguageFilters; | |||
import org.sonar.batch.scan.filesystem.ModuleFileSystemProvider; | |||
public class ModuleScanContainer extends ComponentContainer { | |||
private static final Logger LOG = LoggerFactory.getLogger(ModuleScanContainer.class); | |||
private final Project module; | |||
public ModuleScanContainer(ProjectScanContainer parent, Project module) { | |||
super(parent); | |||
this.module = module; | |||
} | |||
@Override | |||
protected void doBeforeStart() { | |||
LOG.info("------------- Scan {}", module.getName()); | |||
addCoreComponents(); | |||
addExtensions(); | |||
} | |||
private void addCoreComponents() { | |||
ProjectDefinition moduleDefinition = get(ProjectTree.class).getProjectDefinition(module); | |||
add( | |||
moduleDefinition, | |||
module.getConfiguration(), | |||
module, | |||
ProjectSettings.class); | |||
// hack to initialize commons-configuration before ExtensionProviders | |||
get(ProjectSettings.class); | |||
add( | |||
EventBus.class, | |||
Phases.class, | |||
PhasesTimeProfiler.class, | |||
UnsupportedProperties.class, | |||
Phases.getPhaseClasses(), | |||
moduleDefinition.getContainerExtensions(), | |||
// TODO move outside project, but not possible yet because of dependency of project settings (cf plsql) | |||
Languages.class, | |||
// file system | |||
PathResolver.class, | |||
FileExclusions.class, | |||
LanguageFilters.class, | |||
ExclusionFilters.class, | |||
DefaultProjectClasspath.class, | |||
new ModuleFileSystemProvider(), | |||
DeprecatedFileSystemAdapter.class, | |||
FileSystemLogger.class, | |||
// the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor) | |||
get(ResourcePersister.class).getSnapshot(module), | |||
TimeMachineConfiguration.class, | |||
org.sonar.api.database.daos.MeasuresDao.class, | |||
DefaultSensorContext.class, | |||
BatchExtensionDictionnary.class, | |||
DefaultTimeMachine.class, | |||
ViolationFilters.class, | |||
ResourceFilters.class, | |||
DefaultProfileLoader.class, | |||
DryRunExporter.class, | |||
new ProfileProvider()); | |||
} | |||
private void addExtensions() { | |||
ExtensionInstaller installer = get(ExtensionInstaller.class); | |||
installer.install(this, new ExtensionInstaller.ComponentFilter() { | |||
public boolean accept(Object extension) { | |||
if (ExtensionUtils.isType(extension, BatchExtension.class) && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_PROJECT)) { | |||
// Special use-case: the extension point ProjectBuilder is used in a Maven environment to define some | |||
// new sub-projects without pom. | |||
// Example : C# plugin adds sub-projects at runtime, even if they are not defined in root pom. | |||
return !ExtensionUtils.isMavenExtensionOnly(extension) || module.getPom() != null; | |||
} | |||
return false; | |||
} | |||
}); | |||
} | |||
@Override | |||
protected void doAfterStart() { | |||
DefaultIndex index = get(DefaultIndex.class); | |||
index.setCurrentProject(module, | |||
get(ResourceFilters.class), | |||
get(ViolationFilters.class), | |||
get(RulesProfile.class)); | |||
get(Phases.class).execute(module); | |||
} | |||
} |
@@ -0,0 +1,136 @@ | |||
/* | |||
* 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.scan; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.batch.DefaultFileLinesContextFactory; | |||
import org.sonar.batch.DefaultResourceCreationLock; | |||
import org.sonar.batch.ProjectConfigurator; | |||
import org.sonar.batch.ProjectTree; | |||
import org.sonar.batch.bootstrap.ExtensionInstaller; | |||
import org.sonar.batch.bootstrap.ExtensionUtils; | |||
import org.sonar.batch.bootstrap.MetricProvider; | |||
import org.sonar.batch.bootstrap.ProjectExclusions; | |||
import org.sonar.batch.bootstrap.ProjectLock; | |||
import org.sonar.batch.bootstrap.ProjectReactorReady; | |||
import org.sonar.batch.index.DefaultIndex; | |||
import org.sonar.batch.index.DefaultPersistenceManager; | |||
import org.sonar.batch.index.DefaultResourcePersister; | |||
import org.sonar.batch.index.DependencyPersister; | |||
import org.sonar.batch.index.EventPersister; | |||
import org.sonar.batch.index.LinkPersister; | |||
import org.sonar.batch.index.MeasurePersister; | |||
import org.sonar.batch.index.MemoryOptimizer; | |||
import org.sonar.batch.index.SourcePersister; | |||
import org.sonar.batch.scan.maven.FakeMavenPluginExecutor; | |||
import org.sonar.batch.scan.maven.MavenPluginExecutor; | |||
import org.sonar.core.component.ScanGraph; | |||
import org.sonar.core.component.ScanGraphStore; | |||
import org.sonar.core.component.ScanPerspectives; | |||
import org.sonar.core.notification.DefaultNotificationManager; | |||
import org.sonar.core.resource.DefaultResourcePermissions; | |||
import org.sonar.core.test.TestPlanBuilder; | |||
import org.sonar.core.test.TestableBuilder; | |||
public class ProjectScanContainer extends ComponentContainer { | |||
public ProjectScanContainer(ComponentContainer taskContainer) { | |||
super(taskContainer); | |||
} | |||
@Override | |||
protected void doBeforeStart() { | |||
addBatchComponents(); | |||
fixMavenExecutor(); | |||
addBatchExtensions(); | |||
} | |||
private void addBatchComponents() { | |||
add( | |||
DefaultResourceCreationLock.class, | |||
DefaultPersistenceManager.class, | |||
DependencyPersister.class, | |||
EventPersister.class, | |||
LinkPersister.class, | |||
MeasurePersister.class, | |||
MemoryOptimizer.class, | |||
DefaultResourcePermissions.class, | |||
DefaultResourcePersister.class, | |||
SourcePersister.class, | |||
DefaultNotificationManager.class, | |||
MetricProvider.class, | |||
ProjectExclusions.class, | |||
ProjectReactorReady.class, | |||
ProjectTree.class, | |||
ProjectConfigurator.class, | |||
DefaultIndex.class, | |||
DefaultFileLinesContextFactory.class, | |||
ProjectLock.class, | |||
LastSnapshots.class, | |||
ScanGraph.create(), | |||
TestPlanBuilder.class, | |||
TestableBuilder.class, | |||
ScanPerspectives.class, | |||
ScanGraphStore.class | |||
); | |||
} | |||
private void fixMavenExecutor() { | |||
if (get(MavenPluginExecutor.class) == null) { | |||
add(FakeMavenPluginExecutor.class); | |||
} | |||
} | |||
private void addBatchExtensions() { | |||
get(ExtensionInstaller.class).install(this, new ExtensionInstaller.ComponentFilter() { | |||
public boolean accept(Object extension) { | |||
return ExtensionUtils.isType(extension, BatchExtension.class) | |||
&& ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_BATCH); | |||
} | |||
}); | |||
} | |||
@Override | |||
protected void doAfterStart() { | |||
ProjectTree tree = get(ProjectTree.class); | |||
scanRecursively(tree.getRootProject()); | |||
} | |||
private void scanRecursively(Project module) { | |||
for (Project subModules : module.getModules()) { | |||
scanRecursively(subModules); | |||
} | |||
scan(module); | |||
} | |||
private void scan(Project module) { | |||
ModuleScanContainer moduleContainer = new ModuleScanContainer(this, module); | |||
try { | |||
moduleContainer.startComponents(); | |||
} finally { | |||
moduleContainer.stopComponents(); | |||
removeChild(); | |||
} | |||
} | |||
} |
@@ -1,149 +0,0 @@ | |||
/* | |||
* 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.scan; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.BatchExtensionDictionnary; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.profiles.RulesProfile; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.api.scan.filesystem.FileExclusions; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.batch.DefaultProfileLoader; | |||
import org.sonar.batch.DefaultProjectClasspath; | |||
import org.sonar.batch.DefaultSensorContext; | |||
import org.sonar.batch.DefaultTimeMachine; | |||
import org.sonar.batch.ProfileProvider; | |||
import org.sonar.batch.ProjectTree; | |||
import org.sonar.batch.ResourceFilters; | |||
import org.sonar.batch.ViolationFilters; | |||
import org.sonar.batch.bootstrap.Container; | |||
import org.sonar.batch.bootstrap.ExtensionInstaller; | |||
import org.sonar.batch.bootstrap.ProjectSettings; | |||
import org.sonar.batch.bootstrap.UnsupportedProperties; | |||
import org.sonar.batch.components.TimeMachineConfiguration; | |||
import org.sonar.batch.events.EventBus; | |||
import org.sonar.batch.index.DefaultIndex; | |||
import org.sonar.batch.index.ResourcePersister; | |||
import org.sonar.batch.local.DryRunExporter; | |||
import org.sonar.batch.phases.Phases; | |||
import org.sonar.batch.phases.PhasesTimeProfiler; | |||
import org.sonar.batch.scan.filesystem.DeprecatedFileSystemAdapter; | |||
import org.sonar.batch.scan.filesystem.ExclusionFilters; | |||
import org.sonar.batch.scan.filesystem.FileSystemLogger; | |||
import org.sonar.batch.scan.filesystem.LanguageFilters; | |||
import org.sonar.batch.scan.filesystem.ModuleFileSystemProvider; | |||
import org.sonar.core.qualitymodel.DefaultModelFinder; | |||
import org.sonar.jpa.dao.ProfilesDao; | |||
import org.sonar.jpa.dao.RulesDao; | |||
public class ScanContainer extends Container { | |||
private static final Logger LOG = LoggerFactory.getLogger(ScanContainer.class); | |||
private Project project; | |||
public ScanContainer(Project project) { | |||
this.project = project; | |||
} | |||
@Override | |||
protected void configure() { | |||
logSettings(); | |||
addCoreComponents(); | |||
addPluginExtensions(); | |||
} | |||
private void addCoreComponents() { | |||
ProjectDefinition projectDefinition = container.getComponentByType(ProjectTree.class).getProjectDefinition(project); | |||
container.addSingleton(projectDefinition); | |||
container.addSingleton(project.getConfiguration()); | |||
container.addSingleton(project); | |||
container.addSingleton(ProjectSettings.class); | |||
// hack to initialize commons-configuration before ExtensionProviders | |||
container.getComponentByType(ProjectSettings.class); | |||
container.addSingleton(EventBus.class); | |||
container.addSingleton(Phases.class); | |||
container.addSingleton(PhasesTimeProfiler.class); | |||
for (Class clazz : Phases.getPhaseClasses()) { | |||
container.addSingleton(clazz); | |||
} | |||
container.addSingleton(UnsupportedProperties.class); | |||
for (Object component : projectDefinition.getContainerExtensions()) { | |||
container.addSingleton(component); | |||
} | |||
container.addSingleton(Languages.class); | |||
container.addSingleton(RulesDao.class); | |||
container.addSingleton(LastSnapshots.class); | |||
// file system | |||
container.addSingleton(PathResolver.class); | |||
container.addSingleton(FileExclusions.class); | |||
container.addSingleton(LanguageFilters.class); | |||
container.addSingleton(ExclusionFilters.class); | |||
container.addSingleton(DefaultProjectClasspath.class); | |||
container.addPicoAdapter(new ModuleFileSystemProvider()); | |||
container.addSingleton(DeprecatedFileSystemAdapter.class); | |||
container.addSingleton(FileSystemLogger.class); | |||
// the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor) | |||
container.addSingleton(container.getComponentByType(ResourcePersister.class).getSnapshot(project)); | |||
container.addSingleton(TimeMachineConfiguration.class); | |||
container.addSingleton(org.sonar.api.database.daos.MeasuresDao.class); | |||
container.addSingleton(ProfilesDao.class); | |||
container.addSingleton(DefaultSensorContext.class); | |||
container.addSingleton(BatchExtensionDictionnary.class); | |||
container.addSingleton(DefaultTimeMachine.class); | |||
container.addSingleton(ViolationFilters.class); | |||
container.addSingleton(ResourceFilters.class); | |||
container.addSingleton(DefaultModelFinder.class); | |||
container.addSingleton(DefaultProfileLoader.class); | |||
container.addSingleton(DryRunExporter.class); | |||
container.addPicoAdapter(new ProfileProvider()); | |||
} | |||
private void addPluginExtensions() { | |||
ExtensionInstaller installer = container.getComponentByType(ExtensionInstaller.class); | |||
installer.installInspectionExtensions(container); | |||
} | |||
private void logSettings() { | |||
LOG.info("------------- Inspecting {}", project.getName()); | |||
} | |||
/** | |||
* Analyze project | |||
*/ | |||
@Override | |||
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(Phases.class).execute(project); | |||
} | |||
} |
@@ -19,53 +19,33 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.api.task.Task; | |||
import org.sonar.api.task.TaskDefinition; | |||
import org.sonar.batch.ProjectTree; | |||
import org.sonar.batch.tasks.RequiresProject; | |||
import org.sonar.batch.bootstrap.TaskContainer; | |||
@RequiresProject | |||
public class ScanTask implements Task { | |||
public static final String COMMAND = "inspect"; | |||
public static final TaskDefinition DEFINITION = TaskDefinition.create() | |||
.setDescription("Scan project and upload report to server") | |||
.setName("Project Scan") | |||
.setCommand(COMMAND) | |||
.setTask(ScanTask.class); | |||
private final ComponentContainer container; | |||
private final ProjectTree projectTree; | |||
private final ComponentContainer taskContainer; | |||
public ScanTask(ProjectTree projectTree, ComponentContainer container) { | |||
this.container = container; | |||
this.projectTree = projectTree; | |||
public ScanTask(TaskContainer taskContainer) { | |||
this.taskContainer = taskContainer; | |||
} | |||
public void execute() { | |||
scanRecursively(projectTree.getRootProject()); | |||
} | |||
private void scanRecursively(Project project) { | |||
for (Project subProject : project.getModules()) { | |||
scanRecursively(subProject); | |||
} | |||
scan(project); | |||
} | |||
@VisibleForTesting | |||
void scan(Project project) { | |||
ScanContainer projectModule = new ScanContainer(project); | |||
ProjectScanContainer projectScanContainer = new ProjectScanContainer(taskContainer); | |||
try { | |||
ComponentContainer childContainer = container.createChild(); | |||
projectModule.init(childContainer); | |||
projectModule.start(); | |||
projectScanContainer.startComponents(); | |||
} finally { | |||
projectModule.stop(); | |||
container.removeChild(); | |||
projectScanContainer.stopComponents(); | |||
taskContainer.removeChild(); | |||
} | |||
} | |||
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.batch.tasks; | |||
import com.google.common.collect.Maps; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
@@ -32,7 +33,6 @@ import org.sonar.batch.scan.ScanTask; | |||
import javax.annotation.Nullable; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.regex.Pattern; | |||
@@ -44,8 +44,8 @@ public class Tasks implements TaskComponent { | |||
private final TaskDefinition[] taskDefinitions; | |||
private final Settings settings; | |||
private final Map<String, TaskDefinition> taskDefByCommand = new HashMap<String, TaskDefinition>(); | |||
private final Map<Class<? extends Task>, TaskDefinition> taskDefByTask = new HashMap<Class<? extends Task>, TaskDefinition>(); | |||
private final Map<String, TaskDefinition> taskDefByCommand = Maps.newHashMap(); | |||
private final Map<Class<? extends Task>, TaskDefinition> taskDefByTask = Maps.newHashMap(); | |||
public Tasks(Settings settings, TaskDefinition[] taskDefinitions) { | |||
this.settings = settings; | |||
@@ -53,13 +53,9 @@ public class Tasks implements TaskComponent { | |||
} | |||
public TaskDefinition getTaskDefinition(@Nullable String command) { | |||
String finalCommand = command; | |||
if (StringUtils.isBlank(finalCommand)) { | |||
// Try with a property | |||
finalCommand = settings.getString(CoreProperties.TASK); | |||
} | |||
// Default to inspection task | |||
finalCommand = StringUtils.isNotBlank(finalCommand) ? finalCommand : ScanTask.COMMAND; | |||
String finalCommand = StringUtils.defaultIfBlank(command, settings.getString(CoreProperties.TASK)); | |||
finalCommand = StringUtils.defaultIfBlank(finalCommand, ScanTask.COMMAND); | |||
if (taskDefByCommand.containsKey(finalCommand)) { | |||
return taskDefByCommand.get(finalCommand); | |||
} | |||
@@ -71,7 +67,7 @@ public class Tasks implements TaskComponent { | |||
} | |||
/** | |||
* Perform validation of tasks definitions | |||
* Perform validation of task definitions | |||
*/ | |||
public void start() { | |||
for (TaskDefinition def : taskDefinitions) { | |||
@@ -117,7 +113,7 @@ public class Tasks implements TaskComponent { | |||
} | |||
if (taskDefByTask.containsKey(taskClass)) { | |||
throw new SonarException("Task '" + def.getTask().getName() + "' is defined twice: first by '" + taskDefByTask.get(taskClass).getName() + "' and then by '" + def.getName() | |||
+ "'"); | |||
+ "'"); | |||
} | |||
taskDefByTask.put(taskClass, def); | |||
} |
@@ -1,78 +0,0 @@ | |||
/* | |||
* 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; | |||
import org.apache.commons.configuration.PropertiesConfiguration; | |||
import org.junit.Test; | |||
import org.sonar.batch.bootstrap.Container; | |||
import java.util.Properties; | |||
import static org.hamcrest.Matchers.is; | |||
import static org.junit.Assert.assertThat; | |||
public class BatchTest { | |||
@Test | |||
public void shouldExecute() { | |||
FakeModule module = new FakeModule(); | |||
module.init(); | |||
new Batch(module).execute(); | |||
assertThat(module.started, is(true)); | |||
assertThat(module.stopped, is(true)); | |||
} | |||
public static class FakeModule extends Container { | |||
private boolean started=false; | |||
private boolean stopped=false; | |||
@Override | |||
protected void doStart() { | |||
started = true; | |||
} | |||
@Override | |||
protected void doStop() { | |||
if (!started) { | |||
throw new IllegalStateException("Not started"); | |||
} | |||
stopped = true; | |||
} | |||
@Override | |||
protected void configure() { | |||
} | |||
} | |||
@Test | |||
public void shouldConvertCommonsConfigurationToProperties() { | |||
PropertiesConfiguration commonsConf = new PropertiesConfiguration(); | |||
commonsConf.setProperty("foo", "Foo"); | |||
commonsConf.setProperty("list", "One,Two"); | |||
assertThat(commonsConf.getString("list"), is("One")); | |||
assertThat(commonsConf.getStringArray("list")[0], is("One")); | |||
assertThat(commonsConf.getStringArray("list")[1], is("Two")); | |||
Properties props = Batch.convertToProperties(commonsConf); | |||
assertThat(props.getProperty("foo"), is("Foo")); | |||
assertThat(props.getProperty("list"), is("One,Two")); | |||
} | |||
} |
@@ -27,6 +27,7 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
@@ -35,56 +36,55 @@ import static org.mockito.Mockito.when; | |||
public class BatchSettingsTest { | |||
Configuration deprecatedConf; | |||
ServerClient client; | |||
ProjectDefinition project; | |||
ProjectReactor reactor; | |||
BootstrapSettings bootstrapSettings; | |||
ServerClient client = mock(ServerClient.class); | |||
ProjectDefinition project = ProjectDefinition.create().setKey("struts"); | |||
ProjectReactor reactor = new ProjectReactor(project); | |||
Configuration deprecatedConf = new BaseConfiguration(); | |||
BootstrapSettings bootstrapSettings= new BootstrapSettings(new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
@Before | |||
public void before() { | |||
project = ProjectDefinition.create(); | |||
project.setKey("struts"); | |||
reactor = new ProjectReactor(project); | |||
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, new GlobalBatchProperties()); | |||
} | |||
@Test | |||
public void should_load_system_props() { | |||
System.setProperty("BatchSettingsTest.testSystemProp", "system"); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf, | |||
new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
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, new GlobalBatchProperties()); | |||
assertThat(batchSettings.getString("build.prop")).isEqualTo("build"); | |||
public void should_load_project_props() { | |||
project.setProperty("project.prop", "project"); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf, | |||
new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
assertThat(batchSettings.getString("project.prop")).isEqualTo("project"); | |||
} | |||
@Test | |||
public void should_load_global_settings() { | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), reactor, client, deprecatedConf, new GlobalBatchProperties()); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf, | |||
new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
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, new GlobalBatchProperties()); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf, | |||
new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
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, new GlobalBatchProperties()); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf, | |||
new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
Map<String, String> moduleSettings = batchSettings.getModuleProperties("struts-core"); | |||
assertThat(moduleSettings).hasSize(1); | |||
assertThat(moduleSettings.get("sonar.java.coveragePlugin")).isEqualTo("cobertura"); | |||
@@ -94,13 +94,15 @@ 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, new GlobalBatchProperties()); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf, | |||
new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
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, new GlobalBatchProperties()); | |||
BatchSettings batchSettings = new BatchSettings(bootstrapSettings, new PropertyDefinitions(), client, deprecatedConf, | |||
new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
assertThat(deprecatedConf.getString("sonar.cpd.cross")).isEqualTo("true"); | |||
assertThat(deprecatedConf.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco"); |
@@ -19,68 +19,40 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.collect.Lists; | |||
import org.junit.Test; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.batch.maven.MavenPluginHandler; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.batch.scan.maven.FakeMavenPluginExecutor; | |||
import org.sonar.batch.scan.maven.MavenPluginExecutor; | |||
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.core.config.Logback; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
import java.util.Collections; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class BootstrapContainerTest { | |||
private ProjectReactor reactor = new ProjectReactor(ProjectDefinition.create()); | |||
@Test | |||
public void should_register_fake_maven_executor_if_not_maven_env() { | |||
BootstrapContainer module = new BootstrapContainer(reactor, null, MyMavenPluginExecutor.class); | |||
module.init(); | |||
public void should_add_components() { | |||
BootstrapContainer container = BootstrapContainer.create(Collections.emptyList()); | |||
container.doBeforeStart(); | |||
assertThat(module.isMavenPluginExecutorRegistered()).isTrue(); | |||
assertThat(module.container.getComponentByType(MavenPluginExecutor.class)).isInstanceOf(MyMavenPluginExecutor.class); | |||
} | |||
@Test | |||
public void should_use_plugin_executor_provided_by_maven() { | |||
BootstrapContainer module = new BootstrapContainer(reactor); | |||
module.init(); | |||
assertThat(module.isMavenPluginExecutorRegistered()).isFalse(); | |||
assertThat(module.container.getComponentByType(MavenPluginExecutor.class)).isInstanceOf(FakeMavenPluginExecutor.class); | |||
assertThat(container.get(Logback.class)).isNotNull(); | |||
assertThat(container.get(TempDirectories.class)).isNotNull(); | |||
} | |||
@Test | |||
public void should_register_bootstrap_components() { | |||
BootstrapContainer module = new BootstrapContainer(reactor, new FakeComponent()); | |||
module.init(); | |||
public void should_add_bootstrap_extensions() { | |||
BootstrapContainer container = BootstrapContainer.create(Lists.newArrayList(Foo.class, new Bar())); | |||
container.doBeforeStart(); | |||
assertThat(module.container).isNotNull(); | |||
assertThat(module.container.getComponentByType(FakeComponent.class)).isNotNull(); | |||
assertThat(module.container.getComponentByType(ProjectReactor.class)).isSameAs(reactor); | |||
assertThat(container.get(Foo.class)).isNotNull(); | |||
assertThat(container.get(Bar.class)).isNotNull(); | |||
} | |||
@Test | |||
public void should_not_fail_if_no_bootstrap_components() { | |||
BootstrapContainer module = new BootstrapContainer(reactor); | |||
module.init(); | |||
assertThat(module.container).isNotNull(); | |||
assertThat(module.container.getComponentByType(ProjectReactor.class)).isSameAs(reactor); | |||
} | |||
public static class FakeComponent { | |||
public static class Foo implements BatchExtension { | |||
} | |||
public static class MyMavenPluginExecutor implements MavenPluginExecutor { | |||
public void execute(Project project, DefaultModuleFileSystem fs, String goal) { | |||
} | |||
public static class Bar implements BatchExtension { | |||
public MavenPluginHandler execute(Project project, DefaultModuleFileSystem fs, MavenPluginHandler handler) { | |||
return handler; | |||
} | |||
} | |||
} |
@@ -17,23 +17,27 @@ | |||
* 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; | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.annotations.Beta; | |||
import com.google.common.collect.Maps; | |||
import org.junit.Test; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
import java.util.Map; | |||
/** | |||
* The presence of this annotation on a task extension class indicates that the extension | |||
* will be disabled when there is no project available. | |||
* | |||
* @since 3.5 | |||
*/ | |||
@Beta | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
public @interface RequiresProject { | |||
import static org.fest.assertions.Assertions.assertThat; | |||
import static org.fest.assertions.MapAssert.entry; | |||
public class BootstrapPropertiesTest { | |||
@Test | |||
public void test_copy_of_properties() { | |||
Map<String, String> map = Maps.newHashMap(); | |||
map.put("foo", "bar"); | |||
BootstrapProperties wrapper = new BootstrapProperties(map); | |||
assertThat(wrapper.properties()).hasSize(1).includes(entry("foo", "bar")); | |||
assertThat(wrapper.properties()).isNotSameAs(map); | |||
map.put("put", "after_copy"); | |||
assertThat(wrapper.properties()).hasSize(1); | |||
} | |||
} |
@@ -19,35 +19,58 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.collect.ImmutableMap; | |||
import org.junit.Test; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class BootstrapSettingsTest { | |||
@Test | |||
public void shouldLoadBuildModel() { | |||
// this is the project as defined in the build tool | |||
public void project_settings_should_be_optional() { | |||
Map<String, String> props = ImmutableMap.of("foo", "bar"); | |||
BootstrapSettings settings = new BootstrapSettings(new BootstrapProperties(props)); | |||
assertThat(settings.property("foo")).isEqualTo("bar"); | |||
} | |||
@Test | |||
public void should_load_project_settings() { | |||
// this is the project as defined in the bootstrapper | |||
ProjectDefinition project = ProjectDefinition.create(); | |||
project.setProperty("foo", "bar"); | |||
ProjectReactor reactor = new ProjectReactor(project); | |||
BootstrapSettings settings = new BootstrapSettings(reactor, new GlobalBatchProperties()); | |||
BootstrapSettings settings = new BootstrapSettings(new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
assertThat(settings.getProperty("foo")).isEqualTo("bar"); | |||
assertThat(settings.property("foo")).isEqualTo("bar"); | |||
assertThat(settings.properties().size()).isGreaterThan(1); | |||
} | |||
@Test | |||
public void environmentShouldOverrideBuildModel() { | |||
public void environment_should_override_project_settings() { | |||
ProjectDefinition project = ProjectDefinition.create(); | |||
project.setProperty("BootstrapSettingsTest.testEnv", "build"); | |||
System.setProperty("BootstrapSettingsTest.testEnv", "env"); | |||
ProjectReactor reactor = new ProjectReactor(project); | |||
BootstrapSettings settings = new BootstrapSettings(reactor, new GlobalBatchProperties()); | |||
BootstrapSettings settings = new BootstrapSettings(new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
assertThat(settings.property("BootstrapSettingsTest.testEnv")).isEqualTo("env"); | |||
} | |||
@Test | |||
public void should_get_default_value_of_missing_property() { | |||
ProjectDefinition project = ProjectDefinition.create(); | |||
project.setProperty("foo", "bar"); | |||
ProjectReactor reactor = new ProjectReactor(project); | |||
BootstrapSettings settings = new BootstrapSettings(new BootstrapProperties(Collections.<String, String>emptyMap()), reactor); | |||
assertThat(settings.getProperty("BootstrapSettingsTest.testEnv")).isEqualTo("env"); | |||
assertThat(settings.property("foo", "default_value")).isEqualTo("bar"); | |||
assertThat(settings.property("missing", "default_value")).isEqualTo("default_value"); | |||
} | |||
} |
@@ -19,10 +19,12 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
@@ -32,6 +34,7 @@ import org.sonar.api.utils.HttpDownloader; | |||
import org.sonar.api.utils.SonarException; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
import static org.mockito.Mockito.doThrow; | |||
@@ -52,12 +55,15 @@ public class DryRunDatabaseTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
@Before | |||
public void setUp() { | |||
databaseFile = new File("/tmp/dryrun.h2.db"); | |||
public void setUp() throws Exception { | |||
databaseFile = temp.newFile("dryrun.h2.db"); | |||
when(tempDirectories.getFile("", "dryrun.h2.db")).thenReturn(databaseFile); | |||
settings.setProperty(CoreProperties.DRY_RUN, true); | |||
dryRunDatabase = new DryRunDatabase(settings, server, tempDirectories, projectReactor, mock(ProjectReactorReady.class)); | |||
dryRunDatabase = new DryRunDatabase(settings, server, tempDirectories, projectReactor); | |||
} | |||
@Test | |||
@@ -83,7 +89,7 @@ public class DryRunDatabaseTest { | |||
assertThat(settings.getString(DatabaseProperties.PROP_DRIVER)).isEqualTo("org.h2.Driver"); | |||
assertThat(settings.getString(DatabaseProperties.PROP_USER)).isEqualTo("sonar"); | |||
assertThat(settings.getString(DatabaseProperties.PROP_PASSWORD)).isEqualTo("sonar"); | |||
assertThat(settings.getString(DatabaseProperties.PROP_URL)).isEqualTo("jdbc:h2:/tmp/dryrun"); | |||
assertThat(settings.getString(DatabaseProperties.PROP_URL)).isEqualTo("jdbc:h2:" + StringUtils.removeEnd(databaseFile.getAbsolutePath(), ".h2.db")); | |||
} | |||
@Test |
@@ -20,22 +20,17 @@ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.collect.Maps; | |||
import org.apache.commons.lang.ClassUtils; | |||
import org.junit.Test; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.ExtensionProvider; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.api.ServerExtension; | |||
import org.sonar.api.SonarPlugin; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.batch.SupportedEnvironment; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.platform.PluginMetadata; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.api.task.TaskDefinition; | |||
import org.sonar.api.task.TaskExtension; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.batch.tasks.RequiresProject; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
@@ -47,173 +42,123 @@ import static org.mockito.Mockito.when; | |||
public class ExtensionInstallerTest { | |||
private static final PluginMetadata METADATA = mock(PluginMetadata.class); | |||
PluginMetadata metadata = mock(PluginMetadata.class); | |||
private static Map<PluginMetadata, Plugin> newPlugin(final Object... extensions) { | |||
Map<PluginMetadata, Plugin> newPlugin(final Object... extensions) { | |||
Map<PluginMetadata, Plugin> result = Maps.newHashMap(); | |||
result.put(METADATA, | |||
result.put(metadata, | |||
new SonarPlugin() { | |||
public List<?> getExtensions() { | |||
return Arrays.asList(extensions); | |||
} | |||
} | |||
); | |||
); | |||
return result; | |||
} | |||
@Test | |||
public void shouldInstallExtensionsWithBatchInstantiationStrategy() { | |||
public void should_filter_extensions_to_install() { | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(BatchService.class, ProjectService.class, ServerService.class)); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(Foo.class, Bar.class)); | |||
ComponentContainer container = new ComponentContainer(); | |||
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); | |||
installer.install(container, new FooMatcher()); | |||
installer.installBatchExtensions(container, InstantiationStrategy.PER_BATCH); | |||
assertThat(container.getComponentByType(BatchService.class)).isNotNull(); | |||
assertThat(container.getComponentByType(ProjectService.class)).isNull(); | |||
assertThat(container.getComponentByType(ServerService.class)).isNull(); | |||
assertThat(container.get(Foo.class)).isNotNull(); | |||
assertThat(container.get(Bar.class)).isNull(); | |||
} | |||
@Test | |||
public void shouldInstallProvidersWithBatchInstantiationStrategy() { | |||
public void should_execute_extension_provider() { | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(BatchServiceProvider.class, ProjectServiceProvider.class)); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(new FooProvider(), new BarProvider())); | |||
ComponentContainer container = new ComponentContainer(); | |||
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); | |||
installer.installBatchExtensions(container, InstantiationStrategy.PER_BATCH); | |||
installer.install(container, new FooMatcher()); | |||
assertThat(container.getComponentByType(BatchService.class)).isNotNull(); | |||
assertThat(container.getComponentByType(ProjectService.class)).isNull(); | |||
assertThat(container.getComponentByType(ServerService.class)).isNull(); | |||
assertThat(container.get(Foo.class)).isNotNull(); | |||
assertThat(container.get(Bar.class)).isNull(); | |||
} | |||
@Test | |||
public void shouldInstallTaskExtensions() { | |||
public void should_provide_list_of_extensions() { | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(SampleProjectTask.class, SampleTask.class, TaskProvider.class)); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(new FooBarProvider())); | |||
ComponentContainer container = new ComponentContainer(); | |||
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); | |||
installer.installTaskExtensions(container, true); | |||
installer.install(container, new TrueMatcher()); | |||
assertThat(container.getComponentByType(SampleProjectTask.class)).isNotNull(); | |||
assertThat(container.getComponentByType(SampleTask.class)).isNotNull(); | |||
assertThat(container.getComponentByType(AnotherTask.class)).isNotNull(); | |||
assertThat(container.get(Foo.class)).isNotNull(); | |||
assertThat(container.get(Bar.class)).isNotNull(); | |||
} | |||
@Test | |||
public void shouldNotInstallProjectTaskExtensionsWhenNoProject() { | |||
public void should_not_install_on_unsupported_environment() { | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(SampleProjectTask.class, SampleTask.class)); | |||
ComponentContainer container = new ComponentContainer(); | |||
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); | |||
installer.installTaskExtensions(container, false); | |||
assertThat(container.getComponentByType(SampleProjectTask.class)).isNull(); | |||
assertThat(container.getComponentByType(SampleTask.class)).isNotNull(); | |||
} | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(Foo.class, MavenExtension.class, AntExtension.class, new BarProvider())); | |||
@Test | |||
public void shouldInstallTaskDefinitions() { | |||
TaskDefinition definition = TaskDefinition.create(); | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(definition)); | |||
ComponentContainer container = new ComponentContainer(); | |||
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); | |||
installer.installTaskDefinitionExtensions(container); | |||
installer.install(container, new TrueMatcher()); | |||
assertThat(container.getComponentsByType(TaskDefinition.class)).containsExactly(definition); | |||
assertThat(container.get(MavenExtension.class)).isNull(); | |||
assertThat(container.get(AntExtension.class)).isNotNull(); | |||
assertThat(container.get(Foo.class)).isNotNull(); | |||
assertThat(container.get(Bar.class)).isNotNull(); | |||
} | |||
@Test | |||
public void shouldNotInstallPluginsOnNonSupportedEnvironment() { | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(MavenService.class, BuildToolService.class)); | |||
ComponentContainer container = new ComponentContainer(); | |||
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), new Settings()); | |||
installer.installInspectionExtensions(container); | |||
assertThat(container.getComponentByType(MavenService.class)).isNull(); | |||
assertThat(container.getComponentByType(BuildToolService.class)).isNotNull(); | |||
private static class FooMatcher implements ExtensionInstaller.ComponentFilter { | |||
public boolean accept(Object extension) { | |||
return extension.equals(Foo.class) || ClassUtils.isAssignable(Foo.class, extension.getClass()) || ClassUtils.isAssignable(FooProvider.class, extension.getClass()); | |||
} | |||
} | |||
@Test | |||
public void should_disable_maven_extensions_if_virtual_module_in_maven_project() { | |||
Project project = mock(Project.class); | |||
when(project.getPom()).thenReturn(null); | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(MavenService.class)); | |||
private static class TrueMatcher implements ExtensionInstaller.ComponentFilter { | |||
public boolean accept(Object extension) { | |||
return true; | |||
} | |||
} | |||
ComponentContainer container = new ComponentContainer(); | |||
container.addSingleton(project); | |||
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("maven", "2.2.1"), new Settings()); | |||
installer.installInspectionExtensions(container); | |||
public static class Foo implements BatchExtension { | |||
assertThat(container.getComponentByType(MavenService.class)).isNull(); | |||
} | |||
@InstantiationStrategy(InstantiationStrategy.PER_BATCH) | |||
public static class BatchService implements BatchExtension { | |||
public static class Bar implements BatchExtension { | |||
} | |||
public static class ProjectService implements BatchExtension { | |||
@SupportedEnvironment("maven") | |||
public static class MavenExtension implements BatchExtension { | |||
} | |||
public static class ServerService implements ServerExtension { | |||
@SupportedEnvironment("ant") | |||
public static class AntExtension implements BatchExtension { | |||
} | |||
@InstantiationStrategy(InstantiationStrategy.PER_BATCH) | |||
public static class BatchServiceProvider extends ExtensionProvider implements BatchExtension { | |||
public static class FooProvider extends ExtensionProvider implements BatchExtension { | |||
@Override | |||
public Object provide() { | |||
return Arrays.<Object> asList(BatchService.class, ServerService.class); | |||
return new Foo(); | |||
} | |||
} | |||
public static class ProjectServiceProvider extends ExtensionProvider implements BatchExtension { | |||
public static class BarProvider extends ExtensionProvider implements BatchExtension { | |||
@Override | |||
public Object provide() { | |||
return ProjectService.class; | |||
return new Bar(); | |||
} | |||
} | |||
@SupportedEnvironment("maven") | |||
public static class MavenService implements BatchExtension { | |||
} | |||
@SupportedEnvironment({"maven", "ant", "gradle"}) | |||
public static class BuildToolService implements BatchExtension { | |||
} | |||
@RequiresProject | |||
public static class SampleProjectTask implements TaskExtension { | |||
} | |||
public static class SampleTask implements TaskExtension { | |||
} | |||
public static class AnotherTask implements TaskExtension { | |||
} | |||
public static class TaskProvider extends ExtensionProvider implements TaskExtension { | |||
public static class FooBarProvider extends ExtensionProvider implements BatchExtension { | |||
@Override | |||
public Object provide() { | |||
return Arrays.<Object> asList(AnotherTask.class); | |||
return Arrays.asList(new Foo(), new Bar()); | |||
} | |||
} | |||
@@ -23,7 +23,6 @@ import com.google.common.base.Charsets; | |||
import com.google.common.io.Files; | |||
import org.apache.commons.io.IOUtils; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
@@ -53,7 +52,7 @@ import static org.mockito.Mockito.when; | |||
public class ServerClientTest { | |||
MockHttpServer server = null; | |||
BootstrapSettings settings; | |||
BootstrapSettings settings = mock(BootstrapSettings.class); | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
@@ -68,15 +67,10 @@ public class ServerClientTest { | |||
} | |||
} | |||
@Before | |||
public void before(){ | |||
settings = mock(BootstrapSettings.class); | |||
} | |||
@Test | |||
public void should_remove_url_ending_slash() throws Exception { | |||
BootstrapSettings settings = mock(BootstrapSettings.class); | |||
when(settings.getProperty(eq("sonar.host.url"), anyString())).thenReturn("http://localhost:8080/sonar/"); | |||
when(settings.property(eq("sonar.host.url"), anyString())).thenReturn("http://localhost:8080/sonar/"); | |||
ServerClient client = new ServerClient(settings, new EnvironmentInformation("Junit", "4")); | |||
@@ -128,8 +122,8 @@ public class ServerClientTest { | |||
server.start(); | |||
server.setMockResponseStatus(401); | |||
when(settings.getProperty(eq("sonar.login"))).thenReturn("login"); | |||
when(settings.getProperty(eq("sonar.password"))).thenReturn("password"); | |||
when(settings.property(eq("sonar.login"))).thenReturn("login"); | |||
when(settings.property(eq("sonar.password"))).thenReturn("password"); | |||
thrown.expectMessage("Not authorized. Please check the properties sonar.login and sonar.password"); | |||
newServerClient().request("/foo"); | |||
@@ -146,7 +140,7 @@ public class ServerClientTest { | |||
} | |||
private ServerClient newServerClient() { | |||
when(settings.getProperty(eq("sonar.host.url"), anyString())).thenReturn("http://localhost:" + server.getPort()); | |||
when(settings.property(eq("sonar.host.url"), anyString())).thenReturn("http://localhost:" + server.getPort()); | |||
return new ServerClient(settings, new EnvironmentInformation("Junit", "4")); | |||
} | |||
@@ -1,56 +0,0 @@ | |||
/* | |||
* 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.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.SonarException; | |||
import static org.mockito.Mockito.mock; | |||
public class TaskBootstrapContainerTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@Test | |||
public void should_throw_when_no_project_and_task_require_project() { | |||
final ExtensionInstaller extensionInstaller = mock(ExtensionInstaller.class); | |||
Container bootstrapModule = new Container() { | |||
@Override | |||
protected void configure() { | |||
// used to install project extensions | |||
container.addSingleton(extensionInstaller); | |||
container.addSingleton(Settings.class); | |||
} | |||
}; | |||
bootstrapModule.init(); | |||
TaskBootstrapContainer module = new TaskBootstrapContainer("inspect"); | |||
bootstrapModule.installChild(module); | |||
thrown.expect(SonarException.class); | |||
thrown.expectMessage("Task 'Project Scan' requires to be run on a project"); | |||
module.start(); | |||
} | |||
} |
@@ -1,65 +0,0 @@ | |||
/* | |||
* 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.junit.Test; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.task.TaskDefinition; | |||
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 TaskContainerTest { | |||
@Test | |||
public void should_register_task_extensions_when_project_present() { | |||
final ExtensionInstaller extensionInstaller = mock(ExtensionInstaller.class); | |||
Container bootstrapModule = new Container() { | |||
@Override | |||
protected void configure() { | |||
// used to install project extensions | |||
container.addSingleton(extensionInstaller); | |||
} | |||
}; | |||
bootstrapModule.init(); | |||
TaskContainer module = new TaskContainer(TaskDefinition.create(), true); | |||
bootstrapModule.installChild(module); | |||
verify(extensionInstaller).installTaskExtensions(any(ComponentContainer.class), eq(true)); | |||
} | |||
@Test | |||
public void should_register_task_extensions_when_no_project() { | |||
final ExtensionInstaller extensionInstaller = mock(ExtensionInstaller.class); | |||
Container bootstrapModule = new Container() { | |||
@Override | |||
protected void configure() { | |||
// used to install project extensions | |||
container.addSingleton(extensionInstaller); | |||
} | |||
}; | |||
bootstrapModule.init(); | |||
TaskContainer module = new TaskContainer(TaskDefinition.create(), false); | |||
bootstrapModule.installChild(module); | |||
verify(extensionInstaller).installTaskExtensions(any(ComponentContainer.class), eq(false)); | |||
} | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.batch.bootstrapper; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
@@ -41,6 +42,7 @@ public class BatchTest { | |||
.build(); | |||
} | |||
@Ignore | |||
@Test(expected = IllegalStateException.class) | |||
public void shouldFailIfNoEnvironment() { | |||
Batch.builder() | |||
@@ -49,13 +51,6 @@ public class BatchTest { | |||
.build(); | |||
} | |||
public void shouldNotFailIfNoProjectReactor() { | |||
Batch.builder() | |||
.setEnvironment(new EnvironmentInformation("Gradle", "1.0")) | |||
.addComponent("fake") | |||
.build(); | |||
} | |||
@Test(expected = IllegalStateException.class) | |||
public void shouldFailIfNullComponents() { | |||
Batch.builder() |
@@ -1,72 +0,0 @@ | |||
/* | |||
* 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.scan; | |||
import org.apache.commons.configuration.PropertiesConfiguration; | |||
import org.fest.assertions.Assertions; | |||
import org.junit.Test; | |||
import org.mockito.Matchers; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.database.model.Snapshot; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.api.resources.Resource; | |||
import org.sonar.batch.ProjectTree; | |||
import org.sonar.batch.bootstrap.BatchSettings; | |||
import org.sonar.batch.bootstrap.Container; | |||
import org.sonar.batch.bootstrap.ExtensionInstaller; | |||
import org.sonar.batch.bootstrap.ProjectSettings; | |||
import org.sonar.batch.index.ResourcePersister; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
public class ScanContainerTest { | |||
@Test | |||
public void should_register_project_extensions() { | |||
// components injected in the parent container | |||
final Project project = new Project("foo"); | |||
project.setConfiguration(new PropertiesConfiguration()); | |||
final ProjectTree projectTree = mock(ProjectTree.class); | |||
when(projectTree.getProjectDefinition(project)).thenReturn(ProjectDefinition.create()); | |||
final ResourcePersister resourcePersister = mock(ResourcePersister.class); | |||
when(resourcePersister.getSnapshot(Matchers.<Resource>any())).thenReturn(new Snapshot()); | |||
final ExtensionInstaller extensionInstaller = mock(ExtensionInstaller.class); | |||
Container batchModule = new Container() { | |||
@Override | |||
protected void configure() { | |||
container.addSingleton(extensionInstaller); | |||
container.addSingleton(projectTree); | |||
container.addSingleton(resourcePersister); | |||
container.addSingleton(new BatchSettings()); | |||
} | |||
}; | |||
batchModule.init(); | |||
ScanContainer projectModule = new ScanContainer(project); | |||
batchModule.installChild(projectModule); | |||
verify(extensionInstaller).installInspectionExtensions(any(ComponentContainer.class)); | |||
Assertions.assertThat(projectModule.container().getComponentByType(ProjectSettings.class)).isNotNull(); | |||
} | |||
} |
@@ -1,59 +0,0 @@ | |||
/* | |||
* 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.scan; | |||
import org.junit.Test; | |||
import org.mockito.InOrder; | |||
import org.sonar.api.platform.ComponentContainer; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.batch.ProjectTree; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.doNothing; | |||
import static org.mockito.Mockito.inOrder; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.spy; | |||
import static org.mockito.Mockito.when; | |||
public class ScanTaskTest { | |||
@Test | |||
public void should_scan_each_module() { | |||
final Project project = new Project("parent"); | |||
final ProjectTree projectTree = mock(ProjectTree.class); | |||
Project module1 = new Project("module1"); | |||
module1.setParent(project); | |||
Project module2 = new Project("module2"); | |||
module2.setParent(project); | |||
when(projectTree.getRootProject()).thenReturn(project); | |||
ScanTask scanTask = new ScanTask(projectTree, mock(ComponentContainer.class)); | |||
ScanTask spy = spy(scanTask); | |||
doNothing().when(spy).scan(any(Project.class)); | |||
spy.execute(); | |||
InOrder inOrder = inOrder(spy); | |||
inOrder.verify(spy).scan(module1); | |||
inOrder.verify(spy).scan(module2); | |||
inOrder.verify(spy).scan(project); | |||
} | |||
} |
@@ -19,7 +19,8 @@ | |||
*/ | |||
package org.sonar.api.batch.bootstrap; | |||
import org.sonar.api.task.TaskExtension; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
/** | |||
* This extension point allows to change project structure at runtime. It is executed once during task startup. | |||
@@ -33,7 +34,8 @@ import org.sonar.api.task.TaskExtension; | |||
* | |||
* @since 2.9 | |||
*/ | |||
public abstract class ProjectBuilder implements TaskExtension { | |||
@InstantiationStrategy(InstantiationStrategy.PER_BATCH) | |||
public abstract class ProjectBuilder implements BatchExtension { | |||
private ProjectReactor reactor; | |||
@@ -19,16 +19,14 @@ | |||
*/ | |||
package org.sonar.api.measures; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.ServerExtension; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.task.TaskExtension; | |||
import java.util.List; | |||
/** | |||
* @since 1.10 | |||
*/ | |||
@InstantiationStrategy(InstantiationStrategy.PER_BATCH) | |||
public interface Metrics extends BatchExtension, ServerExtension { | |||
public interface Metrics extends TaskExtension, ServerExtension { | |||
List<Metric> getMetrics(); | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.api.platform; | |||
import com.google.common.collect.Iterables; | |||
import org.picocontainer.Characteristics; | |||
import org.picocontainer.ComponentAdapter; | |||
import org.picocontainer.DefaultPicoContainer; | |||
@@ -56,7 +57,7 @@ public class ComponentContainer implements BatchComponent, ServerComponent { | |||
/** | |||
* Create child container | |||
*/ | |||
private ComponentContainer(ComponentContainer parent) { | |||
protected ComponentContainer(ComponentContainer parent) { | |||
this.parent = parent; | |||
this.pico = parent.pico.makeChildContainer(); | |||
this.parent.child = this; | |||
@@ -69,10 +70,20 @@ public class ComponentContainer implements BatchComponent, ServerComponent { | |||
* a component twice is not authorized. | |||
*/ | |||
public final ComponentContainer startComponents() { | |||
doBeforeStart(); | |||
pico.start(); | |||
doAfterStart(); | |||
return this; | |||
} | |||
protected void doBeforeStart() { | |||
} | |||
protected void doAfterStart() { | |||
} | |||
/** | |||
* This method MUST NOT be renamed stop() because the container is registered itself in picocontainer. Starting | |||
* a component twice is not authorized. | |||
@@ -82,6 +93,22 @@ public class ComponentContainer implements BatchComponent, ServerComponent { | |||
return this; | |||
} | |||
/** | |||
* @since 3.5 | |||
*/ | |||
public final ComponentContainer add(Object... objects) { | |||
for (Object object : objects) { | |||
if (object instanceof ComponentAdapter) { | |||
addPicoAdapter((ComponentAdapter) object); | |||
} else if (object instanceof Iterable) { | |||
add(Iterables.toArray((Iterable) object, Object.class)); | |||
} else { | |||
addSingleton(object); | |||
} | |||
} | |||
return this; | |||
} | |||
public final ComponentContainer addSingleton(Object component) { | |||
return addComponent(component, true); | |||
} | |||
@@ -103,7 +130,7 @@ public class ComponentContainer implements BatchComponent, ServerComponent { | |||
} | |||
public final void declareExtension(@Nullable PluginMetadata plugin, Object extension) { | |||
propertyDefinitions.addComponent(extension, plugin!=null ? plugin.getName() : ""); | |||
propertyDefinitions.addComponent(extension, plugin != null ? plugin.getName() : ""); | |||
} | |||
public final ComponentContainer addPicoAdapter(ComponentAdapter adapter) { | |||
@@ -111,6 +138,10 @@ public class ComponentContainer implements BatchComponent, ServerComponent { | |||
return this; | |||
} | |||
public <T> T get(Class<T> key) { | |||
return pico.getComponent(key); | |||
} | |||
public final <T> T getComponentByType(Class<T> tClass) { | |||
return pico.getComponent(tClass); | |||
} |
@@ -31,6 +31,7 @@ import com.google.common.collect.Lists; | |||
import org.sonar.api.BatchExtension; | |||
import org.sonar.api.ServerExtension; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.task.TaskExtension; | |||
import javax.annotation.concurrent.Immutable; | |||
@@ -43,8 +44,7 @@ import java.util.List; | |||
*/ | |||
@Beta | |||
@Immutable | |||
@InstantiationStrategy(InstantiationStrategy.PER_BATCH) | |||
public final class ResourceTypeTree implements BatchExtension, ServerExtension { | |||
public final class ResourceTypeTree implements TaskExtension, ServerExtension { | |||
private List<ResourceType> types; | |||
private ListMultimap<String, String> relations; |
@@ -32,6 +32,7 @@ import com.google.common.collect.Maps; | |||
import com.google.common.collect.Sets; | |||
import org.sonar.api.BatchComponent; | |||
import org.sonar.api.ServerComponent; | |||
import org.sonar.api.task.TaskComponent; | |||
import javax.annotation.Nullable; | |||
@@ -44,7 +45,7 @@ import java.util.Map; | |||
* @since 2.14 | |||
*/ | |||
@Beta | |||
public final class ResourceTypes implements BatchComponent, ServerComponent { | |||
public final class ResourceTypes implements TaskComponent, ServerComponent { | |||
public static final Predicate<ResourceType> AVAILABLE_FOR_FILTERS = new Predicate<ResourceType>() { | |||
public boolean apply(@Nullable ResourceType input) { |
@@ -20,12 +20,18 @@ | |||
package org.sonar.api.platform; | |||
import org.junit.Test; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import static junit.framework.Assert.assertTrue; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.spy; | |||
import static org.mockito.Mockito.verify; | |||
public class ComponentContainerTest { | |||
@@ -38,12 +44,14 @@ public class ComponentContainerTest { | |||
@Test | |||
public void testStartAndStop() { | |||
ComponentContainer container = new ComponentContainer(); | |||
ComponentContainer container = spy(new ComponentContainer()); | |||
container.addSingleton(StartableComponent.class); | |||
container.startComponents(); | |||
assertThat(container.getComponentByType(StartableComponent.class).started).isTrue(); | |||
assertThat(container.getComponentByType(StartableComponent.class).stopped).isFalse(); | |||
verify(container).doBeforeStart(); | |||
verify(container).doAfterStart(); | |||
container.stopComponents(); | |||
assertThat(container.getComponentByType(StartableComponent.class).stopped).isTrue(); | |||
@@ -128,6 +136,29 @@ public class ComponentContainerTest { | |||
assertThat(container.getComponentByType(ComponentWithProperty.class)).isNotNull(); | |||
} | |||
@Test | |||
public void test_add_class() { | |||
ComponentContainer container = new ComponentContainer(); | |||
container.add(ComponentWithProperty.class, SimpleComponent.class); | |||
assertThat(container.get(ComponentWithProperty.class)).isNotNull(); | |||
assertThat(container.get(SimpleComponent.class)).isNotNull(); | |||
} | |||
@Test | |||
public void test_add_collection() { | |||
ComponentContainer container = new ComponentContainer(); | |||
container.add(Arrays.asList(ComponentWithProperty.class, SimpleComponent.class)); | |||
assertThat(container.get(ComponentWithProperty.class)).isNotNull(); | |||
assertThat(container.get(SimpleComponent.class)).isNotNull(); | |||
} | |||
@Test | |||
public void test_add_adapter() { | |||
ComponentContainer container = new ComponentContainer(); | |||
container.add(new SimpleComponentProvider()); | |||
assertThat(container.get(SimpleComponent.class)).isNotNull(); | |||
} | |||
public static class StartableComponent { | |||
public boolean started = false, stopped = false; | |||
@@ -144,4 +175,14 @@ public class ComponentContainerTest { | |||
public static class ComponentWithProperty { | |||
} | |||
public static class SimpleComponent { | |||
} | |||
public static class SimpleComponentProvider extends ProviderAdapter { | |||
public SimpleComponent provide() { | |||
return new SimpleComponent(); | |||
} | |||
} | |||
} |
@@ -30,7 +30,7 @@ class BatchBootstrapController < Api::ApiController | |||
send_data String.from_java_bytes(db_content) | |||
end | |||
# GET /batch_bootstrap/properties?project=<key or id> | |||
# GET /batch_bootstrap/properties?[project=<key or id>] | |||
def properties | |||
json_properties=Property.find(:all, :conditions => ['user_id is null and resource_id is null']).map { |property| to_json_property(property) } | |||
@@ -61,9 +61,13 @@ class BatchBootstrapController < Api::ApiController | |||
private | |||
def load_project | |||
project = Project.by_key(params[:project]) | |||
return access_denied if project && !has_role?(:user, project) | |||
project | |||
if params[:project].present? | |||
project = Project.by_key(params[:project]) | |||
return access_denied if project && !has_role?(:user, project) | |||
project | |||
else | |||
nil | |||
end | |||
end | |||
def to_json_property(property, project_key=nil) |