Support core-plugins in gerrit.war as a repository
Change-Id: Iaaa736699de292a6b341f01bfb1c281e5d5d347a
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java b/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java
index 0a96bfb..fa27964 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java
@@ -20,6 +20,7 @@
import com.google.inject.AbstractModule;
import com.google.inject.internal.UniqueAnnotations;
+import com.googlesource.gerrit.plugins.manager.repository.CorePluginsRepository;
import com.googlesource.gerrit.plugins.manager.repository.JenkinsCiPluginsRepository;
import com.googlesource.gerrit.plugins.manager.repository.PluginsRepository;
@@ -31,6 +32,7 @@
DynamicSet.setOf(binder(), PluginsRepository.class);
DynamicSet.bind(binder(), PluginsRepository.class).to(JenkinsCiPluginsRepository.class);
+ DynamicSet.bind(binder(), PluginsRepository.class).to(CorePluginsRepository.class);
install(PluginsCentralCache.module());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsRepository.java b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsRepository.java
new file mode 100644
index 0000000..5655b19
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/repository/CorePluginsRepository.java
@@ -0,0 +1,145 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.manager.repository;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.gerrit.common.Version;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+public class CorePluginsRepository implements PluginsRepository {
+ private static final Logger log = LoggerFactory
+ .getLogger(CorePluginsRepository.class);
+ private static final String GERRIT_VERSION = Version.getVersion();
+ private final SitePaths site;
+
+ @Inject
+ public CorePluginsRepository(SitePaths site) {
+ this.site = site;
+ }
+
+ static class SelectPluginsFromJar implements Predicate<JarEntry> {
+ @Override
+ public boolean apply(JarEntry entry) {
+ String entryName = entry.getName();
+ return (entryName.startsWith("WEB-INF/plugins") &&
+ entryName.endsWith(".jar"));
+ }
+ }
+
+ static class ExtractPluginInfoFromJarEntry implements
+ Function<JarEntry, PluginInfo> {
+ private String gerritWarFilename;
+
+ public ExtractPluginInfoFromJarEntry(String gerritWarFilename) {
+ this.gerritWarFilename = gerritWarFilename;
+ }
+
+ @Override
+ public PluginInfo apply(JarEntry entry) {
+ try {
+ Path entryName = Paths.get(entry.getName());
+ URI pluginUrl =
+ new URI("jar:file:" + gerritWarFilename + "!/" + entry.getName());
+ try (JarInputStream pluginJar =
+ new JarInputStream(pluginUrl.toURL().openStream())) {
+ Manifest manifestJarEntry = getManifestEntry(pluginJar);
+ if (manifestJarEntry != null) {
+ Attributes pluginAttributes = manifestJarEntry.getMainAttributes();
+ return new PluginInfo(
+ pluginAttributes.getValue("Gerrit-PluginName"),
+ pluginAttributes.getValue("Implementation-Version"), "",
+ pluginUrl.toString());
+ } else {
+ return new PluginInfo(entryName.getFileName().toString(), "", "",
+ pluginUrl.toString());
+ }
+ } catch (IOException e) {
+ log.error("Unable to open plugin " + pluginUrl, e);
+ return null;
+ }
+ } catch (URISyntaxException e) {
+ log.error("Invalid plugin filename", e);
+ return null;
+ }
+ }
+
+ private Manifest getManifestEntry(JarInputStream pluginJar)
+ throws IOException {
+ for (JarEntry entry = pluginJar.getNextJarEntry(); entry != null; entry =
+ pluginJar.getNextJarEntry()) {
+ if (entry.getName().equals("META-INF/MANIFEST.MF")) {
+ return new Manifest(pluginJar);
+ }
+ }
+ return null;
+ }
+ }
+
+ @Override
+ public Collection<PluginInfo> list(String gerritVersion) throws IOException {
+ if (!gerritVersion.equals(GERRIT_VERSION)) {
+ log.warn(
+ "No core plugins available for version {} which is different than " +
+ "the current running Gerrit", gerritVersion);
+ return Collections.emptyList();
+ }
+
+ final Path gerritWarPath = site.gerrit_war;
+ if (gerritWarPath == null) {
+ log.warn("Core plugins not available on non-war Gerrit distributions");
+ return Collections.emptyList();
+ }
+
+ try (JarFile gerritWar = new JarFile(gerritWarPath.toFile())) {
+
+ return FluentIterable
+ .from(Collections.list(gerritWar.entries()))
+ .filter(new SelectPluginsFromJar())
+ .transform(
+ new ExtractPluginInfoFromJarEntry(gerritWarPath.toString()))
+ .filter(new Predicate<PluginInfo>() {
+ @Override
+ public boolean apply(PluginInfo pluginInfo) {
+ return pluginInfo != null;
+ }
+ }).toSortedList(new Comparator<PluginInfo>() {
+ @Override
+ public int compare(PluginInfo a, PluginInfo b) {
+ return a.name.compareTo(b.name);
+ }
+ });
+ }
+ }
+}