Files
gerrit/java/com/google/gerrit/server/plugins/JarPluginProvider.java
Christian Aistleitner 7bfa1c320b When writing temporary plugin files, ensure the directory exists
When adding plugins as streams in PluginIT (which upcoming commits
will do), installing the plugin failed, as the temporary directory
does not exist.

Instead of fixing the caller of `asTemp` to create the directory
before the call, we instead change `asTemp` itself to create the
directory, and can thereby simplify other callers, which also
manually create the directory.

Change-Id: If7962ee2898f52c0db43cf030528a82530a2442b
2020-06-01 08:03:29 +00:00

173 lines
5.8 KiB
Java

// Copyright (C) 2014 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.google.gerrit.server.plugins;
import com.google.common.base.MoreObjects;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.PluginName;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
public class JarPluginProvider implements ServerPluginProvider {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
static final String PLUGIN_TMP_PREFIX = "plugin_";
static final String JAR_EXTENSION = ".jar";
private final Path tmpDir;
private final PluginConfigFactory configFactory;
@Inject
JarPluginProvider(SitePaths sitePaths, PluginConfigFactory configFactory) {
this.tmpDir = sitePaths.tmp_dir;
this.configFactory = configFactory;
}
@Override
public boolean handles(Path srcPath) {
String fileName = srcPath.getFileName().toString();
return fileName.endsWith(JAR_EXTENSION) || fileName.endsWith(JAR_EXTENSION + ".disabled");
}
@Override
public String getPluginName(Path srcPath) {
try {
return MoreObjects.firstNonNull(getJarPluginName(srcPath), PluginUtil.nameOf(srcPath));
} catch (IOException e) {
throw new IllegalArgumentException(
"Invalid plugin file " + srcPath + ": cannot get plugin name", e);
}
}
public static String getJarPluginName(Path srcPath) throws IOException {
try (JarFile jarFile = new JarFile(srcPath.toFile())) {
return jarFile.getManifest().getMainAttributes().getValue("Gerrit-PluginName");
}
}
@Override
public ServerPlugin get(Path srcPath, FileSnapshot snapshot, PluginDescription description)
throws InvalidPluginException {
try {
String name = getPluginName(srcPath);
String extension = getExtension(srcPath);
try (InputStream in = Files.newInputStream(srcPath)) {
Path tmp = PluginUtil.asTemp(in, tempNameFor(name), extension, tmpDir);
return loadJarPlugin(name, srcPath, snapshot, tmp, description);
}
} catch (IOException e) {
throw new InvalidPluginException("Cannot load Jar plugin " + srcPath, e);
}
}
@Override
public String getProviderPluginName() {
return PluginName.GERRIT;
}
private static String getExtension(Path path) {
return getExtension(path.getFileName().toString());
}
private static String getExtension(String name) {
int ext = name.lastIndexOf('.');
return 0 < ext ? name.substring(ext) : "";
}
private static String tempNameFor(String name) {
SimpleDateFormat fmt = new SimpleDateFormat("yyMMdd_HHmm");
return PLUGIN_TMP_PREFIX + name + "_" + fmt.format(new Date()) + "_";
}
public static Path storeInTemp(String pluginName, InputStream in, SitePaths sitePaths)
throws IOException {
return PluginUtil.asTemp(in, tempNameFor(pluginName), ".jar", sitePaths.tmp_dir);
}
private ServerPlugin loadJarPlugin(
String name, Path srcJar, FileSnapshot snapshot, Path tmp, PluginDescription description)
throws IOException, InvalidPluginException, MalformedURLException {
JarFile jarFile = new JarFile(tmp.toFile());
boolean keep = false;
try {
Manifest manifest = jarFile.getManifest();
Plugin.ApiType type = Plugin.getApiType(manifest);
List<URL> urls = new ArrayList<>(2);
String overlay = System.getProperty("gerrit.plugin-classes");
if (overlay != null) {
Path classes = Paths.get(overlay).resolve(name).resolve("main");
if (Files.isDirectory(classes)) {
logger.atInfo().log("plugin %s: including %s", name, classes);
urls.add(classes.toUri().toURL());
}
}
urls.add(tmp.toUri().toURL());
ClassLoader pluginLoader =
URLClassLoader.newInstance(
urls.toArray(new URL[urls.size()]), PluginUtil.parentFor(type));
JarScanner jarScanner = createJarScanner(tmp);
PluginConfig pluginConfig = configFactory.getFromGerritConfig(name);
ServerPlugin plugin =
new ServerPlugin(
name,
description.canonicalUrl,
description.user,
srcJar,
snapshot,
jarScanner,
description.dataDir,
pluginLoader,
pluginConfig.getString("metricsPrefix", null),
description.gerritRuntime);
plugin.setCleanupHandle(new CleanupHandle(tmp, jarFile));
keep = true;
return plugin;
} finally {
if (!keep) {
jarFile.close();
}
}
}
private JarScanner createJarScanner(Path srcJar) throws InvalidPluginException {
try {
return new JarScanner(srcJar);
} catch (IOException e) {
throw new InvalidPluginException("Cannot scan plugin file " + srcJar, e);
}
}
}