]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6383 add method to list plugins to uninstall as PluginMetadata
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 17 Apr 2015 18:46:38 +0000 (20:46 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 21 Apr 2015 07:26:34 +0000 (09:26 +0200)
server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java
server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java
server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java
server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java
sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java
sonar-core/src/main/java/org/sonar/core/plugins/PluginJarInstaller.java

index 93273c9b666ac2e610641cfa43af1615375b547a..be8146b73f1c5da70e87ea5152d450f18eb9a5f3 100644 (file)
  */
 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<File> 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<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);
         }
@@ -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<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();
+    }
+  }
 }
index 5280ee0bb1dcf962e07076b3ba72e790346bbefb..eaf8d6eb2d44522df8eca0d8b14ddcf8e6189fa7 100644 (file)
@@ -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();
index 555ea7fff67b2d2af48706ee2f62f4b0db374690..f8ea22a46c7de1bf28b21b304be9dc5ec9d334b7 100644 (file)
@@ -153,7 +153,7 @@ public final class JRubyFacade {
   }
 
   public List<String> getPluginUninstalls() {
-    return get(ServerPluginJarsInstaller.class).getUninstalls();
+    return get(ServerPluginJarsInstaller.class).getUninstalledPluginFilenames();
   }
 
   public UpdateCenter getUpdatePluginCenter(boolean forceReload) {
index d90b0bc0c765c57cad2f89ca3dd8451969318792..8edde701e283adcb48642f08289f976e1c4e640a 100644 (file)
@@ -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<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
@@ -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
index 9932fbf05a7c870f8a83108c6c46db5360a15d97..5a9fb7c4b312f4dd3b23254654ddf8fe7886f0cd 100644 (file)
@@ -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);
 
index 9005f7a09174672f7366b72508e3faf4605bda23..54b18dc0bc22713ec64b250a1751503c084e334e 100644 (file)
@@ -286,8 +286,7 @@ public class DefaultPluginMetadata implements PluginMetadata, Comparable<PluginM
       return false;
     }
     DefaultPluginMetadata that = (DefaultPluginMetadata) o;
-    return !(key != null ? !key.equals(that.key) : that.key != null);
-
+    return key == null ? that.key == null : key.equals(that.key);
   }
 
   @Override
index 301410df7751af0778e74f2cf451587925dd5d6a..ff90f7f127428d0420f2284eab51b24ca3a618f9 100644 (file)
  */
 package org.sonar.core.plugins;
 
+import com.google.common.base.Function;
 import org.sonar.api.BatchComponent;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.utils.SonarException;
 import org.sonar.updatecenter.common.PluginManifest;
 
 import javax.annotation.Nullable;
-
 import java.io.File;
 import java.io.IOException;
 import java.util.Arrays;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 public abstract class PluginJarInstaller implements BatchComponent, ServerComponent {
 
   protected static final String FAIL_TO_INSTALL_PLUGIN = "Fail to install plugin: ";
@@ -86,4 +88,21 @@ public abstract class PluginJarInstaller implements BatchComponent, ServerCompon
       throw new IllegalStateException("Fail to extract plugin metadata from file: " + file, e);
     }
   }
+
+  public Function<File, DefaultPluginMetadata> fileToPlugin(boolean core) {
+    return core ? jarFileToCorePlugin : jarFileToPlugin;
+  }
+
+  private final Function<File, DefaultPluginMetadata> jarFileToCorePlugin = new Function<File, DefaultPluginMetadata>() {
+    @Override
+    public DefaultPluginMetadata apply(@Nullable File file) {
+      return extractMetadata(checkNotNull(file), true);
+    }
+  };
+  private final Function<File, DefaultPluginMetadata> jarFileToPlugin = new Function<File, DefaultPluginMetadata>() {
+    @Override
+    public DefaultPluginMetadata apply(@Nullable File file) {
+      return extractMetadata(checkNotNull(file), false);
+    }
+  };
 }