*/
package org.sonar.server.plugins;
+import com.google.common.base.Function;
import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.StringUtils;
import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.platform.Server;
import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.server.platform.DefaultServerFileSystem;
import org.sonar.updatecenter.common.PluginReferential;
+import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Lists.newArrayList;
+import static java.lang.String.format;
+import static org.apache.commons.io.FileUtils.cleanDirectory;
+import static org.apache.commons.io.FileUtils.copyFile;
+import static org.apache.commons.io.FileUtils.deleteDirectory;
+import static org.apache.commons.io.FileUtils.deleteQuietly;
+import static org.apache.commons.io.FileUtils.forceMkdir;
+import static org.apache.commons.io.FileUtils.listFiles;
+import static org.apache.commons.io.FileUtils.moveFile;
+import static org.apache.commons.io.FileUtils.moveFileToDirectory;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+
public class ServerPluginJarsInstaller {
private static final Logger LOG = Loggers.get(ServerPluginJarsInstaller.class);
+ private static final String FILE_EXTENSION_JAR = "jar";
+ private static final Joiner SLASH_JOINER = Joiner.on(" / ").skipNulls();
private final Server server;
private final DefaultServerFileSystem fs;
File trashDir = fs.getTrashPluginsDir();
try {
if (trashDir.exists()) {
- FileUtils.deleteDirectory(trashDir);
+ deleteDirectory(trashDir);
}
} catch (IOException e) {
throw new IllegalStateException("Fail to clean the plugin trash directory: " + trashDir, e);
private void loadInstalledPlugins() {
for (File file : fs.getUserPlugins()) {
- DefaultPluginMetadata metadata = installer.extractMetadata(file, false);
- if (StringUtils.isNotBlank(metadata.getKey())) {
+ PluginMetadata metadata = installer.fileToPlugin(false).apply(file);
+ if (isNotBlank(metadata.getKey())) {
loadInstalledPlugin(metadata);
}
}
}
- private void loadInstalledPlugin(DefaultPluginMetadata metadata) {
+ private void loadInstalledPlugin(PluginMetadata metadata) {
if (BLACKLISTED_PLUGINS.contains(metadata.getKey())) {
LOG.warn("Plugin {} is blacklisted. Please uninstall it.", metadata.getName());
} else {
PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
if (existing != null) {
- throw MessageException.of(String.format("Found two files for the same plugin '%s': %s and %s",
+ throw MessageException.of(format("Found two files for the same plugin '%s': %s and %s",
metadata.getKey(), metadata.getFile().getName(), existing.getFile().getName()));
}
}
private void moveDownloadedPlugins() {
if (fs.getDownloadedPluginsDir().exists()) {
- Collection<File> sourceFiles = FileUtils.listFiles(fs.getDownloadedPluginsDir(), new String[] {"jar"}, false);
- for (File sourceFile : sourceFiles) {
+ for (File sourceFile : listJarFiles(fs.getDownloadedPluginsDir())) {
overridePlugin(sourceFile, true);
}
}
private void copyBundledPlugins() {
if (serverUpgradeStatus.isFreshInstall()) {
for (File sourceFile : fs.getBundledPlugins()) {
- DefaultPluginMetadata metadata = installer.extractMetadata(sourceFile, false);
+ PluginMetadata metadata = installer.fileToPlugin(false).apply(sourceFile);
// lib/bundled-plugins should be copied only if the plugin is not already
// available in extensions/plugins
if (!pluginByKeys.containsKey(metadata.getKey())) {
File destFile = new File(destDir, sourceFile.getName());
if (destFile.exists()) {
// plugin with same filename already installed
- FileUtils.deleteQuietly(destFile);
+ deleteQuietly(destFile);
}
try {
if (deleteSource) {
- FileUtils.moveFile(sourceFile, destFile);
+ moveFile(sourceFile, destFile);
} else {
- FileUtils.copyFile(sourceFile, destFile, true);
+ copyFile(sourceFile, destFile, true);
}
} catch (IOException e) {
- LOG.error(String.format("Fail to move or copy plugin: %s to %s",
+ LOG.error(format("Fail to move or copy plugin: %s to %s",
sourceFile.getAbsolutePath(), destFile.getAbsolutePath()), e);
}
- DefaultPluginMetadata metadata = installer.extractMetadata(destFile, false);
- if (StringUtils.isNotBlank(metadata.getKey())) {
+ PluginMetadata metadata = installer.fileToPlugin(false).apply(destFile);
+ if (isNotBlank(metadata.getKey())) {
PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
if (existing != null) {
if (!existing.getFile().getName().equals(destFile.getName())) {
- FileUtils.deleteQuietly(existing.getFile());
+ deleteQuietly(existing.getFile());
}
LOG.info("Plugin " + metadata.getKey() + " replaced by new version");
}
private void loadCorePlugins() {
for (File file : fs.getCorePlugins()) {
- DefaultPluginMetadata metadata = installer.extractMetadata(file, true);
+ PluginMetadata metadata = installer.fileToPlugin(true).apply(file);
PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
if (existing != null) {
throw new IllegalStateException("Found two plugins with the same key '" + metadata.getKey() + "': " + metadata.getFile().getName() + " and "
if (metadata != null && !metadata.isCore()) {
try {
File masterFile = new File(fs.getUserPluginsDir(), metadata.getFile().getName());
- FileUtils.moveFileToDirectory(masterFile, fs.getTrashPluginsDir(), true);
+ moveFileToDirectory(masterFile, fs.getTrashPluginsDir(), true);
} catch (IOException e) {
throw new IllegalStateException("Fail to uninstall plugin: " + pluginKey, e);
}
}
}
- public List<String> getUninstalls() {
- List<String> names = Lists.newArrayList();
- if (fs.getTrashPluginsDir().exists()) {
- List<File> files = (List<File>) FileUtils.listFiles(fs.getTrashPluginsDir(), new String[] {"jar"}, false);
- for (File file : files) {
- names.add(file.getName());
- }
+ public List<String> getUninstalledPluginFilenames() {
+ if (!fs.getTrashPluginsDir().exists()) {
+ return Collections.emptyList();
+ }
+
+ return newArrayList(transform(listJarFiles(fs.getTrashPluginsDir()), FileToName.INSTANCE));
+ }
+
+ /**
+ * @return the list of plugins to be uninstalled as {@link DefaultPluginMetadata} instances
+ */
+ public Collection<DefaultPluginMetadata> getUninstalledPlugins() {
+ if (!fs.getTrashPluginsDir().exists()) {
+ return Collections.emptyList();
}
- return names;
+
+ return newArrayList(transform(listJarFiles(fs.getTrashPluginsDir()), installer.fileToPlugin(false)));
}
public void cancelUninstalls() {
if (fs.getTrashPluginsDir().exists()) {
- List<File> files = (List<File>) FileUtils.listFiles(fs.getTrashPluginsDir(), new String[] {"jar"}, false);
- for (File file : files) {
+ for (File file : listJarFiles(fs.getTrashPluginsDir())) {
try {
- FileUtils.moveFileToDirectory(file, fs.getUserPluginsDir(), false);
+ moveFileToDirectory(file, fs.getUserPluginsDir(), false);
} catch (IOException e) {
throw new IllegalStateException("Fail to cancel plugin uninstalls", e);
}
}
private void deploy(DefaultPluginMetadata plugin) {
- LOG.info("Deploy plugin {}", Joiner.on(" / ").skipNulls().join(plugin.getName(), plugin.getVersion(), plugin.getImplementationBuild()));
+ LOG.info("Deploy plugin {}", SLASH_JOINER.join(plugin.getName(), plugin.getVersion(), plugin.getImplementationBuild()));
if (!plugin.isCompatibleWith(server.getVersion())) {
- throw MessageException.of(String.format(
+ throw MessageException.of(format(
"Plugin %s needs a more recent version of SonarQube than %s. At least %s is expected",
plugin.getKey(), server.getVersion(), plugin.getSonarVersion()));
}
try {
File pluginDeployDir = new File(fs.getDeployedPluginsDir(), plugin.getKey());
- FileUtils.forceMkdir(pluginDeployDir);
- FileUtils.cleanDirectory(pluginDeployDir);
+ forceMkdir(pluginDeployDir);
+ cleanDirectory(pluginDeployDir);
installer.installToDir(plugin, pluginDeployDir);
} catch (IOException e) {
private PluginReferential getPluginReferential() {
return PluginReferentialMetadataConverter.getInstalledPluginReferential(getMetadata());
}
+
+ private static Collection<File> listJarFiles(File pluginDir) {
+ return listFiles(pluginDir, new String[] {FILE_EXTENSION_JAR}, false);
+ }
+
+ private enum FileToName implements Function<File, String> {
+ INSTANCE;
+
+ @Override
+ public String apply(@Nullable File file) {
+ return checkNotNull(file).getName();
+ }
+ }
}
import org.sonar.api.platform.Server;
import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.api.utils.MessageException;
+import org.sonar.core.plugins.DefaultPluginMetadata;
import org.sonar.server.platform.DefaultServerFileSystem;
import java.io.File;
+import java.util.Collection;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
jarsInstaller.install();
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).isEmpty();
+ assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).isEmpty();
}
@Test
jarsInstaller.install();
// do not copy foo 1.0
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(2);
+ assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).hasSize(2);
assertThat(new File(pluginsDir, "foo-plugin-2.0.jar")).exists().isFile();
assertThat(new File(pluginsDir, "bar-plugin-1.0.jar")).exists().isFile();
PluginMetadata plugin = jarsInstaller.getMetadata("foo");
assertThat(plugin.isUseChildFirstClassLoader()).isFalse();
// check that the file is still present in extensions/plugins
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
+ assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).hasSize(1);
assertThat(new File(pluginsDir, "foo-plugin-1.0.jar")).exists().isFile();
}
jarsInstaller.install();
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
+ assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).hasSize(1);
assertThat(FileUtils.listFiles(downloadsDir, new String[] {"jar"}, false)).isEmpty();
assertThat(new File(pluginsDir, "foo-plugin-1.0.jar")).exists().isFile();
}
jarsInstaller.install();
jarsInstaller.uninstall("foo");
+ assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).isEmpty();
+ assertThat(FileUtils.listFiles(trashDir, new String[] {"jar"}, false)).hasSize(1);
+ assertThat(jarsInstaller.getUninstalledPluginFilenames()).containsOnly("foo-plugin-1.0.jar");
+ }
+
+ @Test
+ public void pending_removals_reads_metadata() throws Exception {
+ when(upgradeStatus.isFreshInstall()).thenReturn(false);
+ FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir);
+
+ jarsInstaller.install();
+ jarsInstaller.uninstall("foo");
+
assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).isEmpty();
assertThat(FileUtils.listFiles(trashDir, new String[] {"jar"}, false)).hasSize(1);
- assertThat(jarsInstaller.getUninstalls()).containsOnly("foo-plugin-1.0.jar");
+ Collection<DefaultPluginMetadata> removals = jarsInstaller.getUninstalledPlugins();
+ assertThat(removals).hasSize(1);
+ PluginMetadata metadata = removals.iterator().next();
+ assertThat(metadata.getKey()).isEqualTo("foo");
+ assertThat(metadata.getName()).isEqualTo("Foo");
+ assertThat(metadata.getVersion()).isEqualTo("1.0");
+ assertThat(metadata.getOrganization()).isEqualTo("SonarSource");
+ assertThat(metadata.getOrganizationUrl()).isEqualTo("http://www.sonarsource.org");
+ assertThat(metadata.getLicense()).isEqualTo("LGPL 3");
+ assertThat(metadata.getMainClass()).isEqualTo("foo.Main");
}
@Test
assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
assertThat(FileUtils.listFiles(trashDir, new String[] {"jar"}, false)).hasSize(0);
- assertThat(jarsInstaller.getUninstalls()).isEmpty();
+ assertThat(jarsInstaller.getUninstalledPluginFilenames()).isEmpty();
}
@Test