blob: 7ba1518c5bdd831d3a6f7924c428eaa876eb479e [file] [log] [blame]
// 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());
}
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);
}
});
}
}
}