throw new UnsupportedOperationException();
}
- @Override
- public File getDeployDir() {
- throw new UnsupportedOperationException();
- }
-
@Override
public File getHomeDir() {
throw new UnsupportedOperationException();
package org.sonar.db.plugin;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.commons.lang.builder.ToStringBuilder;
public class PluginDto {
return basePluginKey;
}
- public PluginDto setBasePluginKey(String s) {
+ public PluginDto setBasePluginKey(@Nullable String s) {
this.basePluginKey = s;
return this;
}
/**
* Replaces the incomplete {@link org.sonar.api.platform.ServerFileSystem} as many directories can't be
* published in API.
- *
- * @since 6.0
*/
public interface ServerFileSystem {
*/
File getDataDir();
- /**
- * Directory accessible by scanners through web server
- * @return a directory which may or not exist
- */
- File getDeployDir();
-
/**
* Root directory of the server installation
* @return an existing directory
/**
* The file listing all the installed plugins. Used by scanner only.
* @return an existing file
+ * @deprecated see {@link org.sonar.server.startup.GeneratePluginIndex}
*/
+ @Deprecated
File getPluginIndex();
/**
return dataDir;
}
- @Override
- public File getDeployDir() {
- return deployDir;
- }
-
@Override
public File getDeployedPluginsDir() {
- return new File(getDeployDir(), "plugins");
+ return new File(deployDir, "plugins");
}
@Override
@Override
public File getPluginIndex() {
- return new File(getDeployDir(), "plugins/index.txt");
+ return new File(deployDir, "plugins/index.txt");
}
@Override
import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
import org.sonar.server.plugins.InstalledPluginReferentialFactory;
-import org.sonar.server.plugins.PluginCompression;
+import org.sonar.server.plugins.PluginFileSystem;
import org.sonar.server.plugins.ServerPluginJarExploder;
import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.plugins.WebServerExtensionInstaller;
ServerPluginRepository.class,
ServerPluginJarExploder.class,
PluginLoader.class,
- PluginCompression.class,
+ PluginFileSystem.class,
PluginClassloaderFactory.class,
InstalledPluginReferentialFactory.class,
WebServerExtensionInstaller.class,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.plugins;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.FileUtils;
+import org.sonar.core.platform.PluginInfo;
+
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public class InstalledPlugin {
+ private final PluginInfo plugin;
+ private final FileAndMd5 loadedJar;
+ @Nullable
+ private final FileAndMd5 compressedJar;
+
+ public InstalledPlugin(PluginInfo plugin, FileAndMd5 loadedJar, @Nullable FileAndMd5 compressedJar) {
+ this.plugin = requireNonNull(plugin);
+ this.loadedJar = requireNonNull(loadedJar);
+ this.compressedJar = compressedJar;
+ }
+
+ public PluginInfo getPluginInfo() {
+ return plugin;
+ }
+
+ public FileAndMd5 getLoadedJar() {
+ return loadedJar;
+ }
+
+ @Nullable
+ public FileAndMd5 getCompressedJar() {
+ return compressedJar;
+ }
+
+ @Immutable
+ public static final class FileAndMd5 {
+ private final File file;
+ private final String md5;
+
+ public FileAndMd5(File file) {
+ try (InputStream fis = FileUtils.openInputStream(file)) {
+ this.file = file;
+ this.md5 = DigestUtils.md5Hex(fis);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to compute md5 of " + file, e);
+ }
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public String getMd5() {
+ return md5;
+ }
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.plugins;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.jar.JarInputStream;
-import java.util.jar.Pack200;
-import java.util.zip.GZIPOutputStream;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.platform.RemotePluginFile;
-import org.sonar.core.util.FileUtils;
-
-public class PluginCompression {
- private static final Logger LOG = Loggers.get(PluginCompression.class);
- static final String PROPERTY_PLUGIN_COMPRESSION_ENABLE = "sonar.pluginsCompression.enable";
-
- private final Map<String, RemotePluginFile> compressedPlugins = new HashMap<>();
- private final Configuration configuration;
-
- public PluginCompression(Configuration configuration) {
- this.configuration = configuration;
- }
-
- public void compressJar(String pluginKey, Path sourceDir, Path targetJarFile) {
- if (configuration.getBoolean(PROPERTY_PLUGIN_COMPRESSION_ENABLE).orElse(false)) {
- Path targetPack200Path = FileUtils.getPack200FilePath(targetJarFile);
- Path sourcePack200Path = sourceDir.resolve(targetPack200Path.getFileName());
-
- // check if packed file was deployed alongside the jar. If that's the case, use it instead of generating it (SONAR-10395).
- if (Files.isRegularFile(sourcePack200Path)) {
- try {
- LOG.debug("Found pack200: " + sourcePack200Path);
- Files.copy(sourcePack200Path, targetPack200Path);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to copy pack200 file from " + sourcePack200Path + " to " + targetPack200Path, e);
- }
- } else {
- pack200(targetJarFile, targetPack200Path, pluginKey);
- }
-
- String hash = calculateMd5(targetPack200Path);
- RemotePluginFile compressedPlugin = new RemotePluginFile(targetPack200Path.getFileName().toString(), hash);
- compressedPlugins.put(pluginKey, compressedPlugin);
- }
- }
-
- public Map<String, RemotePluginFile> getPlugins() {
- return new HashMap<>(compressedPlugins);
- }
-
- private static String calculateMd5(Path filePath) {
- try (InputStream fis = new BufferedInputStream(Files.newInputStream(filePath))) {
- return DigestUtils.md5Hex(fis);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to compute hash", e);
- }
- }
-
- private static void pack200(Path jarPath, Path toPath, String pluginKey) {
- Profiler profiler = Profiler.create(LOG);
- profiler.startInfo("Compressing with pack200 plugin: " + pluginKey);
- Pack200.Packer packer = Pack200.newPacker();
-
- try (JarInputStream in = new JarInputStream(new BufferedInputStream(Files.newInputStream(jarPath)));
- OutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(toPath)))) {
- packer.pack(in, out);
- } catch (IOException e) {
- throw new IllegalStateException(String.format("Fail to pack200 plugin [%s] '%s' to '%s'", pluginKey, jarPath, toPath), e);
- }
- profiler.stopInfo();
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.plugins;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.jar.JarInputStream;
+import java.util.jar.Pack200;
+import java.util.zip.GZIPOutputStream;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.server.plugins.InstalledPlugin.FileAndMd5;
+
+import static com.google.common.base.Preconditions.checkState;
+
+@ServerSide
+public class PluginFileSystem {
+
+ public static final String PROPERTY_PLUGIN_COMPRESSION_ENABLE = "sonar.pluginsCompression.enable";
+ private static final Logger LOG = Loggers.get(PluginFileSystem.class);
+
+ private final Configuration configuration;
+ private final Map<String, InstalledPlugin> installedFiles = new HashMap<>();
+
+ public PluginFileSystem(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ /**
+ * @param plugin
+ * @param loadedJar the JAR loaded by classloaders. It differs from {@code plugin.getJarFile()}
+ * which is the initial location of JAR as seen by users
+ */
+ public void addInstalledPlugin(PluginInfo plugin, File loadedJar) {
+ checkState(!installedFiles.containsKey(plugin.getKey()), "Plugin %s is already loaded", plugin.getKey());
+ checkState(loadedJar.exists(), "loadedJar does not exist: %s", loadedJar);
+
+ Optional<File> compressed = compressJar(plugin, loadedJar);
+ InstalledPlugin installedFile = new InstalledPlugin(
+ plugin,
+ new FileAndMd5(loadedJar),
+ compressed.map(FileAndMd5::new).orElse(null));
+ installedFiles.put(plugin.getKey(), installedFile);
+ }
+
+ public Optional<InstalledPlugin> getInstalledPlugin(String pluginKey) {
+ return Optional.ofNullable(installedFiles.get(pluginKey));
+ }
+
+ public Collection<InstalledPlugin> getInstalledFiles() {
+ return installedFiles.values();
+ }
+
+ private Optional<File> compressJar(PluginInfo plugin, File jar) {
+ if (!configuration.getBoolean(PROPERTY_PLUGIN_COMPRESSION_ENABLE).orElse(false)) {
+ return Optional.empty();
+ }
+
+ Path targetPack200 = getPack200Path(jar.toPath());
+ Path sourcePack200Path = getPack200Path(plugin.getNonNullJarFile().toPath());
+
+ // check if packed file was deployed alongside the jar. If that's the case, use it instead of generating it (SONAR-10395).
+ if (sourcePack200Path.toFile().exists()) {
+ try {
+ LOG.debug("Found pack200: " + sourcePack200Path);
+ Files.copy(sourcePack200Path, targetPack200);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to copy pack200 file from " + sourcePack200Path + " to " + targetPack200, e);
+ }
+ } else {
+ pack200(jar.toPath(), targetPack200, plugin.getKey());
+ }
+ return Optional.of(targetPack200.toFile());
+ }
+
+ private static void pack200(Path jarPath, Path toPack200Path, String pluginKey) {
+ Profiler profiler = Profiler.create(LOG);
+ profiler.startInfo("Compressing plugin " + pluginKey + " [pack200]");
+
+ try (JarInputStream in = new JarInputStream(new BufferedInputStream(Files.newInputStream(jarPath)));
+ OutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(toPack200Path)))) {
+ Pack200.newPacker().pack(in, out);
+ } catch (IOException e) {
+ throw new IllegalStateException(String.format("Fail to pack200 plugin [%s] '%s' to '%s'", pluginKey, jarPath, toPack200Path), e);
+ }
+ profiler.stopInfo();
+ }
+
+ private static Path getPack200Path(Path jar) {
+ String jarFileName = jar.getFileName().toString();
+ String filename = jarFileName.substring(0, jarFileName.length() - 3) + "pack.gz";
+ return jar.resolveSibling(filename);
+ }
+}
import java.io.File;
import org.apache.commons.io.FileUtils;
-import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.ZipUtils;
import org.sonar.core.platform.ExplodedPlugin;
import static org.apache.commons.io.FileUtils.forceMkdir;
@ServerSide
-@ComputeEngineSide
public class ServerPluginJarExploder extends PluginJarExploder {
private final ServerFileSystem fs;
- private final PluginCompression pluginCompression;
+ private final PluginFileSystem pluginFileSystem;
- public ServerPluginJarExploder(ServerFileSystem fs, PluginCompression pluginCompression) {
+ public ServerPluginJarExploder(ServerFileSystem fs, PluginFileSystem pluginFileSystem) {
this.fs = fs;
- this.pluginCompression = pluginCompression;
+ this.pluginFileSystem = pluginFileSystem;
}
/**
File jarTarget = new File(toDir, jarSource.getName());
FileUtils.copyFile(jarSource, jarTarget);
- pluginCompression.compressJar(pluginInfo.getKey(), jarSource.toPath().getParent(), jarTarget.toPath());
ZipUtils.unzip(jarSource, toDir, newLibFilter());
- return explodeFromUnzippedDir(pluginInfo.getKey(), jarTarget, toDir);
+ ExplodedPlugin explodedPlugin = explodeFromUnzippedDir(pluginInfo.getKey(), jarTarget, toDir);
+ pluginFileSystem.addInstalledPlugin(pluginInfo, jarTarget);
+ return explodedPlugin;
} catch (Exception e) {
throw new IllegalStateException(String.format(
"Fail to unzip plugin [%s] %s to %s", pluginInfo.getKey(), pluginInfo.getNonNullJarFile().getAbsolutePath(), toDir.getAbsolutePath()), e);
@Override
public void start() {
+ long begin = System.currentTimeMillis();
loadPreInstalledPlugins();
copyBundledPlugins();
moveDownloadedPlugins();
import com.google.common.io.Resources;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.SortedSet;
import java.util.function.Function;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.core.platform.PluginInfo;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.plugin.PluginDto;
-import org.sonar.server.plugins.PluginCompression;
-import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.plugins.InstalledPlugin;
+import org.sonar.server.plugins.PluginFileSystem;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.updatecenter.common.Plugin;
import static com.google.common.collect.ImmutableSortedSet.copyOf;
import static java.lang.String.format;
+import static java.util.Collections.emptyMap;
import static java.util.Collections.singleton;
import static java.util.stream.Collectors.toMap;
-import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_PLUGIN_METADATA_COMPARATOR;
+import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_COMPARATOR;
+import static org.sonar.server.plugins.ws.PluginWSCommons.categoryOrNull;
import static org.sonar.server.plugins.ws.PluginWSCommons.compatiblePluginsByKey;
/**
private static final String ARRAY_PLUGINS = "plugins";
private static final String FIELD_CATEGORY = "category";
- private final ServerPluginRepository pluginRepository;
- private final PluginWSCommons pluginWSCommons;
+ private final PluginFileSystem pluginFileSystem;
private final UpdateCenterMatrixFactory updateCenterMatrixFactory;
private final DbClient dbClient;
- private final PluginCompression compression;
- public InstalledAction(ServerPluginRepository pluginRepository, PluginCompression compression, PluginWSCommons pluginWSCommons,
+ public InstalledAction(PluginFileSystem pluginFileSystem,
UpdateCenterMatrixFactory updateCenterMatrixFactory, DbClient dbClient) {
- this.pluginRepository = pluginRepository;
- this.compression = compression;
- this.pluginWSCommons = pluginWSCommons;
+ this.pluginFileSystem = pluginFileSystem;
this.updateCenterMatrixFactory = updateCenterMatrixFactory;
this.dbClient = dbClient;
}
@Override
public void handle(Request request, Response response) throws Exception {
- Collection<PluginInfo> pluginInfoList = searchPluginInfoList();
- Map<String, PluginDto> pluginDtosByKey;
+ Collection<InstalledPlugin> installedPlugins = loadInstalledPlugins();
+ Map<String, PluginDto> dtosByKey;
try (DbSession dbSession = dbClient.openSession(false)) {
- pluginDtosByKey = dbClient.pluginDao().selectAll(dbSession).stream().collect(toMap(PluginDto::getKee, Function.identity()));
+ dtosByKey = dbClient.pluginDao().selectAll(dbSession).stream().collect(toMap(PluginDto::getKee, Function.identity()));
}
- JsonWriter jsonWriter = response.newJsonWriter();
- jsonWriter.setSerializeEmptys(false);
- jsonWriter.beginObject();
+ JsonWriter json = response.newJsonWriter();
+ json.setSerializeEmptys(false);
+ json.beginObject();
List<String> additionalFields = request.paramAsStrings(WebService.Param.FIELDS);
- writePluginInfoList(jsonWriter, pluginInfoList, additionalFields == null ? Collections.emptyList() : additionalFields, pluginDtosByKey);
+ Map<String, Plugin> updateCenterPlugins = (additionalFields == null || additionalFields.isEmpty()) ? emptyMap() : compatiblePluginsByKey(updateCenterMatrixFactory);
- jsonWriter.endObject();
- jsonWriter.close();
- }
-
- private SortedSet<PluginInfo> searchPluginInfoList() {
- return copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, pluginRepository.getPluginInfos());
+ json.name(ARRAY_PLUGINS);
+ json.beginArray();
+ for (InstalledPlugin installedPlugin : copyOf(NAME_KEY_COMPARATOR, installedPlugins)) {
+ PluginDto pluginDto = dtosByKey.get(installedPlugin.getPluginInfo().getKey());
+ Objects.requireNonNull(pluginDto, () -> format("Plugin %s is installed but not in DB", installedPlugin.getPluginInfo().getKey()));
+ Plugin updateCenterPlugin = updateCenterPlugins.get(installedPlugin.getPluginInfo().getKey());
+ PluginWSCommons.writePluginInfo(json, installedPlugin.getPluginInfo(), categoryOrNull(updateCenterPlugin), pluginDto, installedPlugin);
+ }
+ json.endArray();
+ json.endObject();
+ json.close();
}
- private void writePluginInfoList(JsonWriter jsonWriter, Collection<PluginInfo> pluginInfoList, List<String> additionalFields, Map<String, PluginDto> pluginDtos) {
- Map<String, Plugin> compatiblesPluginsFromUpdateCenter = additionalFields.isEmpty()
- ? Collections.emptyMap()
- : compatiblePluginsByKey(updateCenterMatrixFactory);
- pluginWSCommons.writePluginInfoList(jsonWriter, pluginInfoList, compatiblesPluginsFromUpdateCenter, ARRAY_PLUGINS, pluginDtos, compression.getPlugins());
+ private SortedSet<InstalledPlugin> loadInstalledPlugins() {
+ return copyOf(NAME_KEY_COMPARATOR, pluginFileSystem.getInstalledFiles());
}
}
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import static com.google.common.collect.FluentIterable.from;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.io.Resources.getResource;
+import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_PLUGIN_METADATA_COMPARATOR;
+import static org.sonar.server.plugins.ws.PluginWSCommons.categoryOrNull;
import static org.sonar.server.plugins.ws.PluginWSCommons.compatiblePluginsByKey;
/**
private final UserSession userSession;
private final PluginDownloader pluginDownloader;
private final ServerPluginRepository installer;
- private final PluginWSCommons pluginWSCommons;
private final UpdateCenterMatrixFactory updateCenterMatrixFactory;
private final PluginUninstaller pluginUninstaller;
public PendingAction(UserSession userSession, PluginDownloader pluginDownloader,
- ServerPluginRepository installer, PluginUninstaller pluginUninstaller,
- PluginWSCommons pluginWSCommons, UpdateCenterMatrixFactory updateCenterMatrixFactory) {
+ ServerPluginRepository installer, PluginUninstaller pluginUninstaller, UpdateCenterMatrixFactory updateCenterMatrixFactory) {
this.userSession = userSession;
this.pluginDownloader = pluginDownloader;
this.installer = installer;
this.pluginUninstaller = pluginUninstaller;
- this.pluginWSCommons = pluginWSCommons;
this.updateCenterMatrixFactory = updateCenterMatrixFactory;
}
}
}
- pluginWSCommons.writePluginInfoList(json, newPlugins, compatiblePluginsByKey, ARRAY_INSTALLING);
- pluginWSCommons.writePluginInfoList(json, updatedPlugins, compatiblePluginsByKey, ARRAY_UPDATING);
- pluginWSCommons.writePluginInfoList(json, uninstalledPlugins, compatiblePluginsByKey, ARRAY_REMOVING);
+ writePlugin(json, ARRAY_INSTALLING, newPlugins, compatiblePluginsByKey);
+ writePlugin(json, ARRAY_UPDATING, updatedPlugins, compatiblePluginsByKey);
+ writePlugin(json, ARRAY_REMOVING, uninstalledPlugins, compatiblePluginsByKey);
+ }
+
+ private static void writePlugin(JsonWriter json, String propertyName, Collection<PluginInfo> plugins, Map<String, Plugin> compatiblePluginsByKey) {
+ json.name(propertyName);
+ json.beginArray();
+ for (PluginInfo pluginInfo : ImmutableSortedSet.copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) {
+ Plugin plugin = compatiblePluginsByKey.get(pluginInfo.getKey());
+ PluginWSCommons.writePluginInfo(json, pluginInfo, categoryOrNull(plugin), null, null);
+ }
+ json.endArray();
}
private enum PluginInfoToKey implements Function<PluginInfo, String> {
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
-import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.RemotePluginFile;
import org.sonar.db.plugin.PluginDto;
+import org.sonar.server.plugins.InstalledPlugin;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.server.plugins.edition.EditionBundledPlugins;
import org.sonar.updatecenter.common.Artifact;
import org.sonar.updatecenter.common.UpdateCenter;
import org.sonar.updatecenter.common.Version;
-import static com.google.common.collect.ImmutableSortedSet.copyOf;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
private static final String PROPERTY_KEY = "key";
private static final String PROPERTY_NAME = "name";
private static final String PROPERTY_HASH = "hash";
- private static final String PROPERTY_COMPRESSED_HASH = "compressedHash";
private static final String PROPERTY_FILENAME = "filename";
- private static final String PROPERTY_COMPRESSED_FILENAME = "compressedFilename";
private static final String PROPERTY_SONARLINT_SUPPORTED = "sonarLintSupported";
private static final String PROPERTY_DESCRIPTION = "description";
private static final String PROPERTY_LICENSE = "license";
public static final Ordering<PluginInfo> NAME_KEY_PLUGIN_METADATA_COMPARATOR = Ordering.natural()
.onResultOf(PluginInfo::getName)
.compound(Ordering.natural().onResultOf(PluginInfo::getKey));
+ public static final Comparator<InstalledPlugin> NAME_KEY_COMPARATOR = Comparator
+ .comparing((java.util.function.Function<InstalledPlugin, String>) installedPluginFile -> installedPluginFile.getPluginInfo().getName())
+ .thenComparing(f -> f.getPluginInfo().getKey());
public static final Comparator<Plugin> NAME_KEY_PLUGIN_ORDERING = Ordering.from(CASE_INSENSITIVE_ORDER)
.onResultOf(PluginToName.INSTANCE)
.compound(
public static final Comparator<PluginUpdate> NAME_KEY_PLUGIN_UPDATE_ORDERING = Ordering.from(NAME_KEY_PLUGIN_ORDERING)
.onResultOf(PluginUpdateToPlugin.INSTANCE);
- void writePluginInfo(JsonWriter json, PluginInfo pluginInfo, @Nullable String category, @Nullable PluginDto pluginDto, @Nullable RemotePluginFile compressedPlugin) {
+ public static void writePluginInfo(JsonWriter json, PluginInfo pluginInfo, @Nullable String category, @Nullable PluginDto pluginDto, @Nullable InstalledPlugin installedFile) {
json.beginObject();
-
json.prop(PROPERTY_KEY, pluginInfo.getKey());
json.prop(PROPERTY_NAME, pluginInfo.getName());
- if (pluginDto != null) {
- json.prop(PROPERTY_FILENAME, pluginInfo.getNonNullJarFile().getName());
- json.prop(PROPERTY_SONARLINT_SUPPORTED, pluginInfo.isSonarLintSupported());
- json.prop(PROPERTY_HASH, pluginDto.getFileHash());
- json.prop(PROPERTY_UPDATED_AT, pluginDto.getUpdatedAt());
- }
- if (compressedPlugin != null) {
- json.prop(PROPERTY_COMPRESSED_FILENAME, compressedPlugin.getFilename());
- json.prop(PROPERTY_COMPRESSED_HASH, compressedPlugin.getHash());
- }
-
json.prop(PROPERTY_DESCRIPTION, pluginInfo.getDescription());
Version version = pluginInfo.getVersion();
if (version != null) {
json.prop(PROPERTY_HOMEPAGE_URL, pluginInfo.getHomepageUrl());
json.prop(PROPERTY_ISSUE_TRACKER_URL, pluginInfo.getIssueTrackerUrl());
json.prop(PROPERTY_IMPLEMENTATION_BUILD, pluginInfo.getImplementationBuild());
-
- json.endObject();
- }
-
- public void writePluginInfoList(JsonWriter json, Iterable<PluginInfo> plugins, Map<String, Plugin> compatiblePluginsByKey, String propertyName) {
- writePluginInfoList(json, plugins, compatiblePluginsByKey, propertyName, null, null);
- }
-
- public void writePluginInfoList(JsonWriter json, Iterable<PluginInfo> plugins, Map<String, Plugin> compatiblePluginsByKey, String propertyName,
- @Nullable Map<String, PluginDto> pluginDtos, @Nullable Map<String, RemotePluginFile> compressedPlugins) {
- json.name(propertyName);
- json.beginArray();
- for (PluginInfo pluginInfo : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) {
- PluginDto pluginDto = null;
- if (pluginDtos != null) {
- pluginDto = pluginDtos.get(pluginInfo.getKey());
- Preconditions.checkNotNull(pluginDto, "Plugin %s is installed but not in DB", pluginInfo.getKey());
- }
- RemotePluginFile compressedPlugin = compressedPlugins != null ? compressedPlugins.get(pluginInfo.getKey()) : null;
- Plugin plugin = compatiblePluginsByKey.get(pluginInfo.getKey());
- writePluginInfo(json, pluginInfo, categoryOrNull(plugin), pluginDto, compressedPlugin);
+ if (pluginDto != null) {
+ json.prop(PROPERTY_UPDATED_AT, pluginDto.getUpdatedAt());
}
- json.endArray();
+ if (installedFile != null) {
+ json.prop(PROPERTY_FILENAME, installedFile.getLoadedJar().getFile().getName());
+ json.prop(PROPERTY_SONARLINT_SUPPORTED, installedFile.getPluginInfo().isSonarLintSupported());
+ json.prop(PROPERTY_HASH, installedFile.getLoadedJar().getMd5());
+ }
+ json.endObject();
}
public void writePlugin(JsonWriter jsonWriter, Plugin plugin) {
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-import org.sonar.core.platform.RemotePlugin;
import org.sonar.server.platform.ServerFileSystem;
+import org.sonar.server.plugins.InstalledPlugin;
+import org.sonar.server.plugins.PluginFileSystem;
+/**
+ * The file deploy/plugins/index.txt is required for old versions of SonarLint.
+ * They don't use the web service api/plugins/installed to get the list
+ * of installed plugins.
+ * https://jira.sonarsource.com/browse/SLCORE-146
+ */
@ServerSide
public final class GeneratePluginIndex implements Startable {
private static final Logger LOG = Loggers.get(GeneratePluginIndex.class);
- private final ServerFileSystem fileSystem;
- private final PluginRepository repository;
+ private final ServerFileSystem serverFs;
+ private final PluginFileSystem pluginFs;
- public GeneratePluginIndex(ServerFileSystem fileSystem, PluginRepository repository) {
- this.fileSystem = fileSystem;
- this.repository = repository;
+ public GeneratePluginIndex(ServerFileSystem serverFs, PluginFileSystem pluginFs) {
+ this.serverFs = serverFs;
+ this.pluginFs = pluginFs;
}
@Override
public void start() {
Profiler profiler = Profiler.create(LOG).startInfo("Generate scanner plugin index");
- writeIndex(fileSystem.getPluginIndex());
+ writeIndex(serverFs.getPluginIndex());
profiler.stopDebug();
}
// Nothing to do
}
- void writeIndex(File indexFile) {
+ private void writeIndex(File indexFile) {
try {
FileUtils.forceMkdir(indexFile.getParentFile());
try (Writer writer = new OutputStreamWriter(new FileOutputStream(indexFile), StandardCharsets.UTF_8)) {
- for (PluginInfo pluginInfo : repository.getPluginInfos()) {
- writer.append(RemotePlugin.create(pluginInfo).marshal());
+ for (InstalledPlugin plugin : pluginFs.getInstalledFiles()) {
+ writer.append(toRow(plugin));
writer.append(CharUtils.LF);
}
writer.flush();
throw new IllegalStateException("Unable to generate plugin index at " + indexFile, e);
}
}
+
+ private static String toRow(InstalledPlugin file) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(file.getPluginInfo().getKey())
+ .append(",")
+ .append(file.getPluginInfo().isSonarLintSupported())
+ .append(",")
+ .append(file.getLoadedJar().getFile().getName())
+ .append("|")
+ .append(file.getLoadedJar().getMd5());
+ return sb.toString();
+ }
+
}
*/
package org.sonar.server.startup;
-import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
import org.sonar.api.Startable;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.RemotePlugin;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.plugin.PluginDto;
-import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.plugins.InstalledPlugin;
+import org.sonar.server.plugins.PluginFileSystem;
import static java.util.function.Function.identity;
/**
* Take care to update the 'plugins' table at startup.
*/
+@ServerSide
public class RegisterPlugins implements Startable {
private static final Logger LOG = Loggers.get(RegisterPlugins.class);
- private final ServerPluginRepository repository;
+ private final PluginFileSystem pluginFileSystem;
private final DbClient dbClient;
private final UuidFactory uuidFactory;
private final System2 system;
- public RegisterPlugins(ServerPluginRepository repository, DbClient dbClient, UuidFactory uuidFactory, System2 system) {
- this.repository = repository;
+ public RegisterPlugins(PluginFileSystem pluginFileSystem, DbClient dbClient, UuidFactory uuidFactory, System2 system) {
+ this.pluginFileSystem = pluginFileSystem;
this.dbClient = dbClient;
this.uuidFactory = uuidFactory;
this.system = system;
@Override
public void start() {
Profiler profiler = Profiler.create(LOG).startInfo("Register plugins");
- updateDB(repository.getPluginInfos());
+ updateDB();
profiler.stopDebug();
}
// Nothing to do
}
- private void updateDB(Collection<PluginInfo> pluginInfos) {
+ private void updateDB() {
long now = system.now();
try (DbSession dbSession = dbClient.openSession(false)) {
Map<String, PluginDto> allPreviousPluginsByKey = dbClient.pluginDao().selectAll(dbSession).stream()
.collect(Collectors.toMap(PluginDto::getKee, identity()));
- for (PluginInfo pluginInfo : pluginInfos) {
- RemotePlugin remotePlugin = RemotePlugin.create(pluginInfo);
- String newJarMd5 = remotePlugin.file().getHash();
- PluginDto previousDto = allPreviousPluginsByKey.get(pluginInfo.getKey());
+ for (InstalledPlugin installed : pluginFileSystem.getInstalledFiles()) {
+ PluginInfo info = installed.getPluginInfo();
+ PluginDto previousDto = allPreviousPluginsByKey.get(info.getKey());
if (previousDto == null) {
- LOG.debug("Register new plugin {}", pluginInfo.getKey());
+ LOG.debug("Register new plugin {}", info.getKey());
PluginDto pluginDto = new PluginDto()
.setUuid(uuidFactory.create())
- .setKee(pluginInfo.getKey())
- .setBasePluginKey(pluginInfo.getBasePlugin())
- .setFileHash(newJarMd5)
+ .setKee(info.getKey())
+ .setBasePluginKey(info.getBasePlugin())
+ .setFileHash(installed.getLoadedJar().getMd5())
.setCreatedAt(now)
.setUpdatedAt(now);
dbClient.pluginDao().insert(dbSession, pluginDto);
- } else if (!previousDto.getFileHash().equals(newJarMd5)) {
- LOG.debug("Update plugin {}", pluginInfo.getKey());
+ } else if (!previousDto.getFileHash().equals(installed.getLoadedJar().getMd5())) {
+ LOG.debug("Update plugin {}", info.getKey());
previousDto
- .setBasePluginKey(pluginInfo.getBasePlugin())
- .setFileHash(newJarMd5)
+ .setBasePluginKey(info.getBasePlugin())
+ .setFileHash(installed.getLoadedJar().getMd5())
.setUpdatedAt(now);
dbClient.pluginDao().update(dbSession, previousDto);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.plugins;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PluginCompressionTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private MapSettings settings = new MapSettings();
- private Path targetJarPath;
- private Path targetFolder;
- private Path sourceFolder;
-
- private PluginCompression underTest;
-
- @Before
- public void setUp() throws IOException {
- sourceFolder = temp.newFolder("source").toPath();
- targetFolder = temp.newFolder("target").toPath();
- targetJarPath = targetFolder.resolve("test.jar");
- Files.createFile(targetJarPath);
- }
-
- @Test
- public void disable_if_proparty_not_set() throws IOException {
- underTest = new PluginCompression(settings.asConfig());
- underTest.compressJar("key", sourceFolder, targetJarPath);
-
- assertThat(Files.list(targetFolder)).containsOnly(targetJarPath);
- assertThat(underTest.getPlugins()).isEmpty();
- }
-
- @Test
- public void should_compress_plugin() throws IOException {
- settings.setProperty(PluginCompression.PROPERTY_PLUGIN_COMPRESSION_ENABLE, true);
- underTest = new PluginCompression(settings.asConfig());
- underTest.compressJar("key", targetFolder, targetJarPath);
-
- assertThat(Files.list(targetFolder)).containsOnly(targetJarPath, targetFolder.resolve("test.pack.gz"));
- assertThat(underTest.getPlugins()).hasSize(1);
- assertThat(underTest.getPlugins().get("key").getFilename()).isEqualTo("test.pack.gz");
- }
-
- @Test
- public void should_use_deployed_packed_file() throws IOException {
- Path packedPath = sourceFolder.resolve("test.pack.gz");
- Files.write(packedPath, new byte[] {1, 2, 3});
-
- settings.setProperty(PluginCompression.PROPERTY_PLUGIN_COMPRESSION_ENABLE, true);
- underTest = new PluginCompression(settings.asConfig());
- underTest.compressJar("key", sourceFolder, targetJarPath);
-
- assertThat(Files.list(targetFolder)).containsOnly(targetJarPath, targetFolder.resolve("test.pack.gz"));
- assertThat(underTest.getPlugins()).hasSize(1);
- assertThat(underTest.getPlugins().get("key").getFilename()).isEqualTo("test.pack.gz");
-
- // check that the file was copied, not generated
- assertThat(targetFolder.resolve("test.pack.gz")).hasSameContentAs(packedPath);
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.plugins;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.RandomStringUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.core.platform.PluginInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.plugins.PluginFileSystem.PROPERTY_PLUGIN_COMPRESSION_ENABLE;
+
+public class PluginFileSystemTest {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private MapSettings settings = new MapSettings();
+ private Path targetJarPath;
+ private Path targetFolder;
+ private Path sourceFolder;
+
+ @Before
+ public void setUp() throws IOException {
+ sourceFolder = temp.newFolder("source").toPath();
+ targetFolder = temp.newFolder("target").toPath();
+ targetJarPath = targetFolder.resolve("test.jar");
+ Files.createFile(targetJarPath);
+ }
+
+ @Test
+ public void add_plugin_to_list_of_installed_plugins() throws IOException {
+ File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar");
+ PluginInfo info = new PluginInfo("foo");
+
+ PluginFileSystem underTest = new PluginFileSystem(settings.asConfig());
+ underTest.addInstalledPlugin(info, jar);
+
+ assertThat(underTest.getInstalledFiles()).hasSize(1);
+ InstalledPlugin installedPlugin = underTest.getInstalledPlugin("foo").get();
+ assertThat(installedPlugin.getCompressedJar()).isNull();
+ assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(jar.toPath());
+ assertThat(installedPlugin.getPluginInfo()).isSameAs(info);
+ }
+
+ @Test
+ public void compress_jar_if_compression_enabled() throws IOException {
+ File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar");
+ PluginInfo info = new PluginInfo("foo").setJarFile(jar);
+ // the JAR is copied somewhere else in order to be loaded by classloaders
+ File loadedJar = touch(temp.newFolder(), "sonar-foo-plugin.jar");
+
+ settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true);
+ PluginFileSystem underTest = new PluginFileSystem(settings.asConfig());
+ underTest.addInstalledPlugin(info, loadedJar);
+
+ assertThat(underTest.getInstalledFiles()).hasSize(1);
+
+ InstalledPlugin installedPlugin = underTest.getInstalledPlugin("foo").get();
+ assertThat(installedPlugin.getPluginInfo()).isSameAs(info);
+ assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(loadedJar.toPath());
+ assertThat(installedPlugin.getCompressedJar().getFile())
+ .exists()
+ .isFile()
+ .hasName("sonar-foo-plugin.pack.gz")
+ .hasParent(loadedJar.getParentFile());
+ }
+
+ @Test
+ public void copy_and_use_existing_packed_jar_if_compression_enabled() throws IOException {
+ File jar = touch(temp.newFolder(), "sonar-foo-plugin.jar");
+ File packedJar = touch(jar.getParentFile(), "sonar-foo-plugin.pack.gz");
+ PluginInfo info = new PluginInfo("foo").setJarFile(jar);
+ // the JAR is copied somewhere else in order to be loaded by classloaders
+ File loadedJar = touch(temp.newFolder(), "sonar-foo-plugin.jar");
+
+ settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true);
+ PluginFileSystem underTest = new PluginFileSystem(settings.asConfig());
+ underTest.addInstalledPlugin(info, loadedJar);
+
+ assertThat(underTest.getInstalledFiles()).hasSize(1);
+
+ InstalledPlugin installedPlugin = underTest.getInstalledPlugin("foo").get();
+ assertThat(installedPlugin.getPluginInfo()).isSameAs(info);
+ assertThat(installedPlugin.getLoadedJar().getFile().toPath()).isEqualTo(loadedJar.toPath());
+ assertThat(installedPlugin.getCompressedJar().getFile())
+ .exists()
+ .isFile()
+ .hasName(packedJar.getName())
+ .hasParent(loadedJar.getParentFile())
+ .hasSameContentAs(packedJar);
+ }
+
+ private static File touch(File dir, String filename) throws IOException {
+ File file = new File(dir, filename);
+ FileUtils.write(file, RandomStringUtils.random(10));
+ return file;
+ }
+
+ //
+ // @Test
+ // public void should_use_deployed_packed_file() throws IOException {
+ // Path packedPath = sourceFolder.resolve("test.pack.gz");
+ // Files.write(packedPath, new byte[] {1, 2, 3});
+ //
+ // settings.setProperty(PROPERTY_PLUGIN_COMPRESSION_ENABLE, true);
+ // underTest = new PluginFileSystem(settings.asConfig());
+ // underTest.compressJar("key", sourceFolder, targetJarPath);
+ //
+ // assertThat(Files.list(targetFolder)).containsOnly(targetJarPath, targetFolder.resolve("test.pack.gz"));
+ // assertThat(underTest.getPlugins()).hasSize(1);
+ // assertThat(underTest.getPlugins().get("key").getFilename()).isEqualTo("test.pack.gz");
+ //
+ // // check that the file was copied, not generated
+ // assertThat(targetFolder.resolve("test.pack.gz")).hasSameContentAs(packedPath);
+ // }
+
+}
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- ServerFileSystem fs = mock(ServerFileSystem.class);
- PluginCompression pluginCompression = mock(PluginCompression.class);
- ServerPluginJarExploder underTest = new ServerPluginJarExploder(fs, pluginCompression);
+ private ServerFileSystem fs = mock(ServerFileSystem.class);
+ private PluginFileSystem pluginFileSystem = mock(PluginFileSystem.class);
+ private ServerPluginJarExploder underTest = new ServerPluginJarExploder(fs, pluginFileSystem);
@Test
public void copy_all_classloader_files_to_dedicated_directory() throws Exception {
File deployDir = temp.newFolder();
when(fs.getDeployedPluginsDir()).thenReturn(deployDir);
- File jar = TestProjectUtils.jarOf("test-libs-plugin");
- PluginInfo info = PluginInfo.create(jar);
+ File sourceJar = TestProjectUtils.jarOf("test-libs-plugin");
+ PluginInfo info = PluginInfo.create(sourceJar);
ExplodedPlugin exploded = underTest.explode(info);
assertThat(lib).exists().isFile();
assertThat(lib.getCanonicalPath()).startsWith(pluginDeployDir.getCanonicalPath());
}
- verify(pluginCompression).compressJar(info.getKey(), jar.toPath().getParent(), exploded.getMain().toPath());
+ File targetJar = new File(fs.getDeployedPluginsDir(), "testlibs/test-libs-plugin-0.1-SNAPSHOT.jar");
+ verify(pluginFileSystem).addInstalledPlugin(info, targetJar);
}
}
package org.sonar.server.plugins.ws;
import com.google.common.base.Optional;
+import com.hazelcast.com.eclipsesource.json.Json;
+import com.hazelcast.com.eclipsesource.json.JsonObject;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.IOException;
import java.util.Random;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
+import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Action;
-import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.System2;
import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.RemotePluginFile;
import org.sonar.db.DbTester;
-import org.sonar.server.plugins.PluginCompression;
-import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.plugins.InstalledPlugin;
+import org.sonar.server.plugins.InstalledPlugin.FileAndMd5;
+import org.sonar.server.plugins.PluginFileSystem;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.server.ws.WsActionTester;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.UpdateCenter;
import org.sonar.updatecenter.common.Version;
-import static com.google.common.collect.ImmutableList.of;
+import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@Rule
public ExpectedException expectedException = ExpectedException.none();
-
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
- private ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
private UpdateCenterMatrixFactory updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class, RETURNS_DEEP_STUBS);
- private PluginCompression pluginCompression = mock(PluginCompression.class);
- private InstalledAction underTest = new InstalledAction(pluginRepository, pluginCompression, new PluginWSCommons(), updateCenterMatrixFactory, db.getDbClient());
+ private PluginFileSystem pluginFileSystem = mock(PluginFileSystem.class);
+ private InstalledAction underTest = new InstalledAction(pluginFileSystem, updateCenterMatrixFactory, db.getDbClient());
private WsActionTester tester = new WsActionTester(underTest);
@Test
}
@Test
- public void empty_fields_are_not_serialized_to_json() {
- when(pluginRepository.getPluginInfos()).thenReturn(
- of(new PluginInfo("").setName("").setJarFile(new File(""))));
+ public void empty_fields_are_not_serialized_to_json() throws IOException {
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(
+ singletonList(newInstalledPlugin(new PluginInfo("foo")
+ .setName("")
+ .setDescription("")
+ .setLicense("")
+ .setOrganizationName("")
+ .setOrganizationUrl("")
+ .setImplementationBuild("")
+ .setHomepageUrl("")
+ .setIssueTrackerUrl(""))));
db.pluginDbTester().insertPlugin(
- p -> p.setKee(""),
- p -> p.setFileHash("abcdA"),
- p -> p.setUpdatedAt(111111L));
+ p -> p.setKee("foo"),
+ p -> p.setUpdatedAt(100L));
String response = tester.newRequest().execute().getInput();
+ JsonObject json = Json.parse(response).asObject().get("plugins").asArray().get(0).asObject();
+ assertThat(json.get("key")).isNotNull();
+ assertThat(json.get("name")).isNull();
+ assertThat(json.get("description")).isNull();
+ assertThat(json.get("license")).isNull();
+ assertThat(json.get("organizationName")).isNull();
+ assertThat(json.get("organizationUrl")).isNull();
+ assertThat(json.get("homepageUrl")).isNull();
+ assertThat(json.get("issueTrackerUrl")).isNull();
- assertThat(response).doesNotContain("name").doesNotContain("key");
+ }
+
+ private InstalledPlugin newInstalledPlugin(PluginInfo plugin) throws IOException {
+ FileAndMd5 jar = new FileAndMd5(temp.newFile());
+ return new InstalledPlugin(plugin.setJarFile(jar.getFile()), jar, null);
+ }
+
+ private InstalledPlugin newInstalledPluginWithCompression(PluginInfo plugin) throws IOException {
+ FileAndMd5 jar = new FileAndMd5(temp.newFile());
+ FileAndMd5 compressedJar = new FileAndMd5(temp.newFile());
+ return new InstalledPlugin(plugin.setJarFile(jar.getFile()), jar, compressedJar);
}
@Test
- public void verify_properties_displayed_in_json_per_plugin() throws Exception {
- String jarFilename = getClass().getSimpleName() + "/" + "some.jar";
- when(pluginRepository.getPluginInfos()).thenReturn(of(
- new PluginInfo("plugKey")
- .setName("plugName")
- .setDescription("desc_it")
- .setVersion(Version.create("1.0"))
- .setLicense("license_hey")
- .setOrganizationName("org_name")
- .setOrganizationUrl("org_url")
- .setHomepageUrl("homepage_url")
- .setIssueTrackerUrl("issueTracker_url")
- .setImplementationBuild("sou_rev_sha1")
- .setSonarLintSupported(true)
- .setJarFile(new File(getClass().getResource(jarFilename).toURI()))));
+ public void return_default_fields() throws Exception {
+ InstalledPlugin plugin = newInstalledPlugin(new PluginInfo("foo")
+ .setName("plugName")
+ .setDescription("desc_it")
+ .setVersion(Version.create("1.0"))
+ .setLicense("license_hey")
+ .setOrganizationName("org_name")
+ .setOrganizationUrl("org_url")
+ .setHomepageUrl("homepage_url")
+ .setIssueTrackerUrl("issueTracker_url")
+ .setImplementationBuild("sou_rev_sha1")
+ .setSonarLintSupported(true));
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(singletonList(plugin));
db.pluginDbTester().insertPlugin(
- p -> p.setKee("plugKey"),
- p -> p.setFileHash("abcdplugKey"),
- p -> p.setUpdatedAt(111111L));
+ p -> p.setKee(plugin.getPluginInfo().getKey()),
+ p -> p.setUpdatedAt(100L));
String response = tester.newRequest().execute().getInput();
" \"plugins\":" +
" [" +
" {" +
- " \"key\": \"plugKey\"," +
+ " \"key\": \"foo\"," +
" \"name\": \"plugName\"," +
" \"description\": \"desc_it\"," +
" \"version\": \"1.0\"," +
" \"issueTrackerUrl\": \"issueTracker_url\"," +
" \"implementationBuild\": \"sou_rev_sha1\"," +
" \"sonarLintSupported\": true," +
- " \"filename\": \"some.jar\"," +
- " \"hash\": \"abcdplugKey\"," +
- " \"updatedAt\": 111111" +
+ " \"filename\": \"" + plugin.getLoadedJar().getFile().getName() + "\"," +
+ " \"hash\": \"" + plugin.getLoadedJar().getMd5() + "\"," +
+ " \"updatedAt\": 100" +
" }" +
" ]" +
"}");
}
@Test
- public void add_compressed_plugin_info() throws Exception {
- RemotePluginFile compressedInfo = new RemotePluginFile("compressed.pack.gz", "hash");
- when(pluginCompression.getPlugins()).thenReturn(Collections.singletonMap("plugKey", compressedInfo));
+ public void return_compression_fields_if_available() throws Exception {
+ InstalledPlugin plugin = newInstalledPluginWithCompression(new PluginInfo("foo")
+ .setName("plugName")
+ .setDescription("desc_it")
+ .setVersion(Version.create("1.0"))
+ .setLicense("license_hey")
+ .setOrganizationName("org_name")
+ .setOrganizationUrl("org_url")
+ .setHomepageUrl("homepage_url")
+ .setIssueTrackerUrl("issueTracker_url")
+ .setImplementationBuild("sou_rev_sha1")
+ .setSonarLintSupported(true));
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(singletonList(plugin));
- String jarFilename = getClass().getSimpleName() + "/" + "some.jar";
- when(pluginRepository.getPluginInfos()).thenReturn(of(
- new PluginInfo("plugKey")
- .setName("plugName")
- .setDescription("desc_it")
- .setVersion(Version.create("1.0"))
- .setLicense("license_hey")
- .setOrganizationName("org_name")
- .setOrganizationUrl("org_url")
- .setHomepageUrl("homepage_url")
- .setIssueTrackerUrl("issueTracker_url")
- .setImplementationBuild("sou_rev_sha1")
- .setSonarLintSupported(true)
- .setJarFile(new File(getClass().getResource(jarFilename).toURI()))));
db.pluginDbTester().insertPlugin(
- p -> p.setKee("plugKey"),
- p -> p.setFileHash("abcdplugKey"),
- p -> p.setUpdatedAt(111111L));
+ p -> p.setKee(plugin.getPluginInfo().getKey()),
+ p -> p.setUpdatedAt(100L));
String response = tester.newRequest().execute().getInput();
" \"plugins\":" +
" [" +
" {" +
- " \"key\": \"plugKey\"," +
+ " \"key\": \"foo\"," +
" \"name\": \"plugName\"," +
" \"description\": \"desc_it\"," +
" \"version\": \"1.0\"," +
" \"license\": \"license_hey\"," +
- " \"compressedFilename\": \"compressed.pack.gz\"," +
- " \"compressedHash\": \"hash\"," +
" \"organizationName\": \"org_name\"," +
" \"organizationUrl\": \"org_url\",\n" +
" \"editionBundled\": false," +
" \"issueTrackerUrl\": \"issueTracker_url\"," +
" \"implementationBuild\": \"sou_rev_sha1\"," +
" \"sonarLintSupported\": true," +
- " \"filename\": \"some.jar\"," +
- " \"hash\": \"abcdplugKey\"," +
- " \"updatedAt\": 111111" +
+ " \"filename\": \"" + plugin.getLoadedJar().getFile().getName() + "\"," +
+ " \"hash\": \"" + plugin.getLoadedJar().getMd5() + "\"," +
+ " \"updatedAt\": 100" +
" }" +
" ]" +
"}");
@Test
public void category_is_returned_when_in_additional_fields() throws Exception {
String jarFilename = getClass().getSimpleName() + "/" + "some.jar";
- when(pluginRepository.getPluginInfos()).thenReturn(of(
- new PluginInfo("plugKey")
+ File jar = new File(getClass().getResource(jarFilename).toURI());
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(asList(
+ new InstalledPlugin(new PluginInfo("plugKey")
.setName("plugName")
.setDescription("desc_it")
.setVersion(Version.create("1.0"))
.setHomepageUrl("homepage_url")
.setIssueTrackerUrl("issueTracker_url")
.setImplementationBuild("sou_rev_sha1")
- .setJarFile(new File(getClass().getResource(jarFilename).toURI()))));
+ .setJarFile(jar), new FileAndMd5(jar), null)));
UpdateCenter updateCenter = mock(UpdateCenter.class);
when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.of(updateCenter));
when(updateCenter.findAllCompatiblePlugins()).thenReturn(
- Arrays.asList(
+ asList(
Plugin.factory("plugKey")
.setCategory("cat_1")));
p -> p.setUpdatedAt(111111L));
String response = tester.newRequest()
- .setParam(Param.FIELDS, "category")
+ .setParam(WebService.Param.FIELDS, "category")
.execute().getInput();
assertJson(response).isSimilarTo(
}
@Test
- public void plugins_are_sorted_by_name_then_key_and_only_one_plugin_can_have_a_specific_name() {
- when(pluginRepository.getPluginInfos()).thenReturn(
- of(
+ public void plugins_are_sorted_by_name_then_key_and_only_one_plugin_can_have_a_specific_name() throws IOException {
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(
+ asList(
plugin("A", "name2"),
plugin("B", "name1"),
plugin("C", "name0"),
Random random = new Random();
String organization = random.nextBoolean() ? "SonarSource" : "SONARSOURCE";
String pluginKey = "plugKey";
- when(pluginRepository.getPluginInfos()).thenReturn(of(
- new PluginInfo(pluginKey)
+ File jar = new File(getClass().getResource(jarFilename).toURI());
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(asList(
+ new InstalledPlugin(new PluginInfo(pluginKey)
.setName("plugName")
.setVersion(Version.create("1.0"))
.setLicense(license)
.setOrganizationName(organization)
.setImplementationBuild("sou_rev_sha1")
- .setJarFile(new File(getClass().getResource(jarFilename).toURI()))));
+ .setJarFile(jar), new FileAndMd5(jar), null)));
db.pluginDbTester().insertPlugin(
p -> p.setKee(pluginKey),
p -> p.setFileHash("abcdplugKey"),
}
@Test
- public void only_one_plugin_can_have_a_specific_name_and_key() {
- when(pluginRepository.getPluginInfos()).thenReturn(
- of(
+ public void only_one_plugin_can_have_a_specific_name_and_key() throws IOException {
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(
+ asList(
plugin("A", "name2"),
plugin("A", "name2")));
assertThat(response).containsOnlyOnce("name2");
}
- private PluginInfo plugin(String key, String name) {
- return new PluginInfo(key).setName(name).setVersion(Version.create("1.0")).setJarFile(new File("sonar-" + key + "-plugin-1.0.jar"));
+ private InstalledPlugin plugin(String key, String name) throws IOException {
+ File file = temp.newFile();
+ PluginInfo info = new PluginInfo(key)
+ .setName(name)
+ .setVersion(Version.create("1.0"));
+ info.setJarFile(file);
+ return new InstalledPlugin(info, new FileAndMd5(file), null);
}
}
private ServerPluginRepository serverPluginRepository = mock(ServerPluginRepository.class);
private UpdateCenterMatrixFactory updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class, RETURNS_DEEP_STUBS);
private PendingAction underTest = new PendingAction(userSession, pluginDownloader, serverPluginRepository,
- pluginUninstaller, new PluginWSCommons(), updateCenterMatrixFactory);
+ pluginUninstaller, updateCenterMatrixFactory);
private Request request = mock(Request.class);
private WsTester.TestResponse response = new WsTester.TestResponse();
package org.sonar.server.plugins.ws;
import java.io.File;
+import java.io.IOException;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.RemotePluginFile;
import org.sonar.db.plugin.PluginDto;
+import org.sonar.server.plugins.InstalledPlugin;
+import org.sonar.server.plugins.InstalledPlugin.FileAndMd5;
import org.sonar.server.ws.WsTester;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.PluginUpdate;
public class PluginWSCommonsTest {
- WsTester.TestResponse response = new WsTester.TestResponse();
- JsonWriter jsonWriter = response.newJsonWriter();
- PluginWSCommons underTest = new PluginWSCommons();
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private WsTester.TestResponse response = new WsTester.TestResponse();
+ private JsonWriter jsonWriter = response.newJsonWriter();
+ private PluginWSCommons underTest = new PluginWSCommons();
@Test
public void verify_properties_written_by_writePluginMetadata() {
- underTest.writePluginInfo(jsonWriter, gitPluginInfo(), null, null, null);
+ PluginWSCommons.writePluginInfo(jsonWriter, gitPluginInfo(), null, null, null);
jsonWriter.close();
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo("{" +
@Test
public void verify_properties_written_by_writePluginMetadata_with_dto() {
- PluginDto pluginDto = new PluginDto().setFileHash("abcdef123456").setUpdatedAt(123456L);
- underTest.writePluginInfo(jsonWriter, gitPluginInfo(), null, pluginDto, null);
+ PluginDto pluginDto = new PluginDto().setUpdatedAt(123456L);
+ PluginWSCommons.writePluginInfo(jsonWriter, gitPluginInfo(), null, pluginDto, null);
jsonWriter.close();
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo("{" +
" \"organizationUrl\": \"http://www.sonarsource.com\"," +
" \"homepageUrl\": \"https://redirect.sonarsource.com/plugins/scmgit.html\"," +
" \"issueTrackerUrl\": \"http://jira.sonarsource.com/browse/SONARSCGIT\"," +
- " \"filename\": \"sonar-scm-git-plugin-1.0.jar\"," +
- " \"hash\": \"abcdef123456\"," +
- " \"sonarLintSupported\": true," +
" \"updatedAt\": 123456" +
"}");
}
@Test
- public void verify_properties_written_by_writeMetadata_with_compressed_plugin() {
- PluginDto pluginDto = new PluginDto().setFileHash("abcdef123456").setUpdatedAt(123456L);
- RemotePluginFile compressedPlugin = new RemotePluginFile("compressed.pack.gz", "hash");
- underTest.writePluginInfo(jsonWriter, gitPluginInfo(), null, pluginDto, compressedPlugin);
+ public void verify_properties_written_by_writeMetadata_with_compressed_plugin() throws IOException {
+ PluginDto dto = new PluginDto().setUpdatedAt(100L);
+ FileAndMd5 loadedJar = new FileAndMd5(temp.newFile());
+ FileAndMd5 compressedJar = new FileAndMd5(temp.newFile());
+ InstalledPlugin installedFile = new InstalledPlugin(gitPluginInfo(), loadedJar, compressedJar);
+
+ PluginWSCommons.writePluginInfo(jsonWriter, gitPluginInfo(), null, dto, installedFile);
jsonWriter.close();
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo("{" +
- " \"key\": \"scmgit\"," +
- " \"name\": \"Git\"," +
- " \"description\": \"Git SCM Provider.\"," +
- " \"version\": \"1.0\"," +
- " \"license\": \"GNU LGPL 3\"," +
- " \"organizationName\": \"SonarSource\"," +
- " \"compressedFilename\": \"compressed.pack.gz\"," +
- " \"compressedHash\": \"hash\"," +
- " \"organizationUrl\": \"http://www.sonarsource.com\"," +
- " \"homepageUrl\": \"https://redirect.sonarsource.com/plugins/scmgit.html\"," +
- " \"issueTrackerUrl\": \"http://jira.sonarsource.com/browse/SONARSCGIT\"," +
- " \"filename\": \"sonar-scm-git-plugin-1.0.jar\"," +
- " \"hash\": \"abcdef123456\"," +
- " \"sonarLintSupported\": true," +
- " \"updatedAt\": 123456" +
+ " \"key\": \"scmgit\"," +
+ " \"name\": \"Git\"," +
+ " \"description\": \"Git SCM Provider.\"," +
+ " \"version\": \"1.0\"," +
+ " \"license\": \"GNU LGPL 3\"," +
+ " \"organizationName\": \"SonarSource\"," +
+ " \"organizationUrl\": \"http://www.sonarsource.com\"," +
+ " \"homepageUrl\": \"https://redirect.sonarsource.com/plugins/scmgit.html\"," +
+ " \"issueTrackerUrl\": \"http://jira.sonarsource.com/browse/SONARSCGIT\"," +
+ " \"sonarLintSupported\": true," +
+ " \"updatedAt\": 100," +
+ " \"filename\": \"" + loadedJar.getFile().getName() + "\"," +
+ " \"hash\": \"" + loadedJar.getMd5() + "\"" +
"}");
}
@Test
public void verify_properties_written_by_writeMetadata() {
- underTest.writePluginInfo(jsonWriter, gitPluginInfo(), "cat_1", null, null);
+ PluginWSCommons.writePluginInfo(jsonWriter, gitPluginInfo(), "cat_1", null, null);
jsonWriter.close();
assertJson(response.outputAsString()).withStrictArrayOrder().isSimilarTo("{" +
import java.io.File;
import java.io.IOException;
-import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
import org.sonar.server.platform.ServerFileSystem;
+import org.sonar.server.plugins.InstalledPlugin;
+import org.sonar.server.plugins.InstalledPlugin.FileAndMd5;
+import org.sonar.server.plugins.PluginFileSystem;
+import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- private ServerFileSystem fileSystem = mock(ServerFileSystem.class);
+ private ServerFileSystem serverFileSystem = mock(ServerFileSystem.class);
+ private PluginFileSystem pluginFileSystem = mock(PluginFileSystem.class);
private File index;
@Before
public void createIndexFile() throws IOException {
index = temp.newFile();
- when(fileSystem.getPluginIndex()).thenReturn(index);
+ when(serverFileSystem.getPluginIndex()).thenReturn(index);
}
@Test
public void shouldWriteIndex() throws IOException {
- PluginRepository repository = mock(PluginRepository.class);
- PluginInfo sqale = newInfo("sqale");
- PluginInfo checkstyle = newInfo("checkstyle");
- when(repository.getPluginInfos()).thenReturn(Arrays.asList(sqale, checkstyle));
+ InstalledPlugin javaPlugin = newInstalledPlugin("java", true);
+ InstalledPlugin gitPlugin = newInstalledPlugin("scmgit", false);
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(asList(javaPlugin, gitPlugin));
- GeneratePluginIndex underTest = new GeneratePluginIndex(fileSystem, repository);
+ GeneratePluginIndex underTest = new GeneratePluginIndex(serverFileSystem, pluginFileSystem);
underTest.start();
- underTest.stop(); // For coverage
List<String> lines = FileUtils.readLines(index);
- assertThat(lines).hasSize(2);
- assertThat(lines.get(0)).contains("sqale");
- assertThat(lines.get(1)).contains("checkstyle");
+ assertThat(lines).containsExactly(
+ "java,true," + javaPlugin.getLoadedJar().getFile().getName() + "|" + javaPlugin.getLoadedJar().getMd5(),
+ "scmgit,false," + gitPlugin.getLoadedJar().getFile().getName() + "|" + gitPlugin.getLoadedJar().getMd5());
+
+ underTest.stop();
}
@Test(expected = IllegalStateException.class)
File wrongParent = temp.newFile();
wrongParent.createNewFile();
File wrongIndex = new File(wrongParent, "index.txt");
- when(fileSystem.getPluginIndex()).thenReturn(wrongIndex);
-
- PluginRepository repository = mock(PluginRepository.class);
+ when(serverFileSystem.getPluginIndex()).thenReturn(wrongIndex);
- new GeneratePluginIndex(fileSystem, repository).start();
+ new GeneratePluginIndex(serverFileSystem, pluginFileSystem).start();
}
- private PluginInfo newInfo(String pluginKey) throws IOException {
- return new PluginInfo(pluginKey).setJarFile(temp.newFile(pluginKey + ".jar"));
+ private InstalledPlugin newInstalledPlugin(String key, boolean supportSonarLint) throws IOException {
+ FileAndMd5 jar = new FileAndMd5(temp.newFile());
+ PluginInfo pluginInfo = new PluginInfo(key).setJarFile(jar.getFile()).setSonarLintSupported(supportSonarLint);
+ return new InstalledPlugin(pluginInfo, jar, null);
}
}
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import javax.annotation.Nullable;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
-import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.plugins.InstalledPlugin;
+import org.sonar.server.plugins.PluginFileSystem;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.mock;
@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
- DbClient dbClient = dbTester.getDbClient();
-
- private ServerPluginRepository serverPluginRepository;
- private UuidFactory uuidFactory;
- private System2 system2;
+ private DbClient dbClient = dbTester.getDbClient();
+ private PluginFileSystem pluginFileSystem = mock(PluginFileSystem.class);
+ private UuidFactory uuidFactory = mock(UuidFactory.class);
+ private System2 system2 = mock(System2.class);
@Before
- public void prepare() {
- serverPluginRepository = mock(ServerPluginRepository.class);
- uuidFactory = mock(UuidFactory.class);
- system2 = mock(System2.class);
+ public void setUp() {
when(system2.now()).thenReturn(12345L).thenThrow(new IllegalStateException("Should be called only once"));
}
FileUtils.write(fakeJavaJar, "fakejava", StandardCharsets.UTF_8);
File fakeJavaCustomJar = temp.newFile();
FileUtils.write(fakeJavaCustomJar, "fakejavacustom", StandardCharsets.UTF_8);
- when(serverPluginRepository.getPluginInfos()).thenReturn(asList(new PluginInfo("java").setJarFile(fakeJavaJar),
- new PluginInfo("javacustom").setJarFile(fakeJavaCustomJar).setBasePlugin("java")));
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(asList(
+ newPlugin("java", fakeJavaJar, null),
+ newPlugin("javacustom", fakeJavaCustomJar, "java")));
when(uuidFactory.create()).thenReturn("a").thenReturn("b").thenThrow(new IllegalStateException("Should be called only twice"));
- RegisterPlugins register = new RegisterPlugins(serverPluginRepository, dbClient, uuidFactory, system2);
+ RegisterPlugins register = new RegisterPlugins(pluginFileSystem, dbClient, uuidFactory, system2);
register.start();
- register.stop(); // For coverage
+
dbTester.assertDbUnit(getClass(), "insert_new_plugins-result.xml", "plugins");
+
+ register.stop();
}
/**
File fakeJavaCustomJar = temp.newFile();
FileUtils.write(fakeJavaCustomJar, "fakejavacustomchanged", StandardCharsets.UTF_8);
- when(serverPluginRepository.getPluginInfos()).thenReturn(asList(new PluginInfo("javacustom").setJarFile(fakeJavaCustomJar).setBasePlugin("java2")));
+ when(pluginFileSystem.getInstalledFiles()).thenReturn(asList(
+ newPlugin("javacustom", fakeJavaCustomJar, "java2")));
- new RegisterPlugins(serverPluginRepository, dbClient, uuidFactory, system2).start();
+ new RegisterPlugins(pluginFileSystem, dbClient, uuidFactory, system2).start();
dbTester.assertDbUnit(getClass(), "update_only_changed_plugins-result.xml", "plugins");
}
+ private static InstalledPlugin newPlugin(String key, File file, @Nullable String basePlugin) {
+ InstalledPlugin.FileAndMd5 jar = new InstalledPlugin.FileAndMd5(file);
+ PluginInfo info = new PluginInfo(key)
+ .setBasePlugin(basePlugin)
+ .setJarFile(file);
+ return new InstalledPlugin(info, jar, null);
+ }
+
}
return useChildFirstClassLoader;
}
- @CheckForNull
public boolean isSonarLintSupported() {
return sonarLintSupported;
}