From: Sébastien Lesaint Date: Fri, 17 Apr 2015 18:46:38 +0000 (+0200) Subject: SONAR-6383 add method to list plugins to uninstall as PluginMetadata X-Git-Tag: 5.2-RC1~2182 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=bcc4ccf38746f15217ec7424eddd219138d0a37c;p=sonarqube.git SONAR-6383 add method to list plugins to uninstall as PluginMetadata --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java index 93273c9b666..be8146b73f1 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java @@ -19,11 +19,9 @@ */ 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; @@ -35,18 +33,36 @@ import org.sonar.core.plugins.DefaultPluginMetadata; 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; @@ -78,7 +94,7 @@ public class ServerPluginJarsInstaller { 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); @@ -87,20 +103,20 @@ public class ServerPluginJarsInstaller { 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())); } } @@ -108,8 +124,7 @@ public class ServerPluginJarsInstaller { private void moveDownloadedPlugins() { if (fs.getDownloadedPluginsDir().exists()) { - Collection sourceFiles = FileUtils.listFiles(fs.getDownloadedPluginsDir(), new String[] {"jar"}, false); - for (File sourceFile : sourceFiles) { + for (File sourceFile : listJarFiles(fs.getDownloadedPluginsDir())) { overridePlugin(sourceFile, true); } } @@ -118,7 +133,7 @@ public class ServerPluginJarsInstaller { 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())) { @@ -133,26 +148,26 @@ public class ServerPluginJarsInstaller { 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"); } @@ -161,7 +176,7 @@ public class ServerPluginJarsInstaller { 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 " @@ -181,30 +196,37 @@ public class ServerPluginJarsInstaller { 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 getUninstalls() { - List names = Lists.newArrayList(); - if (fs.getTrashPluginsDir().exists()) { - List files = (List) FileUtils.listFiles(fs.getTrashPluginsDir(), new String[] {"jar"}, false); - for (File file : files) { - names.add(file.getName()); - } + public List 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 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 files = (List) 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); } @@ -219,18 +241,18 @@ public class ServerPluginJarsInstaller { } 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) { @@ -249,4 +271,17 @@ public class ServerPluginJarsInstaller { private PluginReferential getPluginReferential() { return PluginReferentialMetadataConverter.getInstalledPluginReferential(getMetadata()); } + + private static Collection listJarFiles(File pluginDir) { + return listFiles(pluginDir, new String[] {FILE_EXTENSION_JAR}, false); + } + + private enum FileToName implements Function { + INSTANCE; + + @Override + public String apply(@Nullable File file) { + return checkNotNull(file).getName(); + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java index 5280ee0bb1d..eaf8d6eb2d4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java @@ -83,7 +83,7 @@ public class PendingPluginsWsAction implements PluginsWsAction { private void writeRemoving(JsonWriter jsonWriter) { jsonWriter.name(ARRAY_REMOVING); jsonWriter.beginArray(); - for (String fileName : copyOf(CASE_INSENSITIVE_ORDER, serverPluginJarsInstaller.getUninstalls())) { + for (String fileName : copyOf(CASE_INSENSITIVE_ORDER, serverPluginJarsInstaller.getUninstalledPluginFilenames())) { writeArchive(jsonWriter, fileName); } jsonWriter.endArray(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index 555ea7fff67..f8ea22a46c7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -153,7 +153,7 @@ public final class JRubyFacade { } public List getPluginUninstalls() { - return get(ServerPluginJarsInstaller.class).getUninstalls(); + return get(ServerPluginJarsInstaller.class).getUninstalledPluginFilenames(); } public UpdateCenter getUpdatePluginCenter(boolean forceReload) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java index d90b0bc0c76..8edde701e28 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java @@ -30,9 +30,11 @@ import org.sonar.api.platform.PluginMetadata; 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; @@ -100,7 +102,7 @@ public class ServerPluginJarsInstallerTest { jarsInstaller.install(); - assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).isEmpty(); + assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).isEmpty(); } @Test @@ -114,7 +116,7 @@ public class ServerPluginJarsInstallerTest { 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"); @@ -137,7 +139,7 @@ public class ServerPluginJarsInstallerTest { 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(); } @@ -173,7 +175,7 @@ public class ServerPluginJarsInstallerTest { 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(); } @@ -246,9 +248,31 @@ public class ServerPluginJarsInstallerTest { 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 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 @@ -262,7 +286,7 @@ public class ServerPluginJarsInstallerTest { 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 diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java index 9932fbf05a7..5a9fb7c4b31 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java @@ -95,7 +95,7 @@ public class PendingPluginsWsActionTest { @Test public void verify_properties_displayed_in_json_per_removing_plugin() throws Exception { - when(serverPluginJarsInstaller.getUninstalls()).thenReturn(of("removed_file.jar")); + when(serverPluginJarsInstaller.getUninstalledPluginFilenames()).thenReturn(of("removed_file.jar")); underTest.handle(request, response); @@ -147,7 +147,7 @@ public class PendingPluginsWsActionTest { @Test public void removing_plugin_are_sorted_and_unique() throws Exception { - when(serverPluginJarsInstaller.getUninstalls()).thenReturn(of("file2.jar", "file0.jar", "file0.jar", "file1.jar")); + when(serverPluginJarsInstaller.getUninstalledPluginFilenames()).thenReturn(of("file2.jar", "file0.jar", "file0.jar", "file1.jar")); underTest.handle(request, response); diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java b/sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java index 9005f7a0917..54b18dc0bc2 100644 --- a/sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java +++ b/sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java @@ -286,8 +286,7 @@ public class DefaultPluginMetadata implements PluginMetadata, Comparable fileToPlugin(boolean core) { + return core ? jarFileToCorePlugin : jarFileToPlugin; + } + + private final Function jarFileToCorePlugin = new Function() { + @Override + public DefaultPluginMetadata apply(@Nullable File file) { + return extractMetadata(checkNotNull(file), true); + } + }; + private final Function jarFileToPlugin = new Function() { + @Override + public DefaultPluginMetadata apply(@Nullable File file) { + return extractMetadata(checkNotNull(file), false); + } + }; }