Allow plugins to contribute InitStep to Gerrit init.
Plugin has to include a class that implements
com.google.gerrit.pgm.init.InitStep and specifying
the class name into the Plugin MANIFEST.MF.
Plugin InitStep is getting instantiated using the
Gerrit PGM injector and then is able to access
the same init objects.
Example:
--------
public class InitJira implements InitStep {
private ConsoleUI ui;
@Inject
public InitJira(final ConsoleUI ui, final Section.Factory sections) {
this.ui = ui;
this.sections = sections;
}
@Override
public void run() throws Exception {
ui.header("Jira integration");
// Jira-specific init steps.
Section jira = sections.get("link", "jira");
// Jira-specific link expansions
}
}
MANIFEST.MF:
------------
Gerrit-InitStep: com.googlesource.plugins.jira.InitJira
Change-Id: I84fcb9acd6845c706961657219a14570e2060b0f
Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com>
This commit is contained in:
committed by
Shawn O. Pearce
parent
f121c1bff1
commit
737285df3f
@@ -32,8 +32,8 @@ class InitAuth implements InitStep {
|
||||
@Inject
|
||||
InitAuth(final ConsoleUI ui, final Section.Factory sections) {
|
||||
this.ui = ui;
|
||||
this.auth = sections.get("auth");
|
||||
this.ldap = sections.get("ldap");
|
||||
this.auth = sections.get("auth", null);
|
||||
this.ldap = sections.get("ldap", null);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
@@ -31,7 +31,7 @@ class InitCache implements InitStep {
|
||||
@Inject
|
||||
InitCache(final SitePaths site, final Section.Factory sections) {
|
||||
this.site = site;
|
||||
this.cache = sections.get("cache");
|
||||
this.cache = sections.get("cache", null);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
@@ -44,7 +44,7 @@ class InitContainer implements InitStep {
|
||||
final Section.Factory sections) {
|
||||
this.ui = ui;
|
||||
this.site = site;
|
||||
this.container = sections.get("container");
|
||||
this.container = sections.get("container", null);
|
||||
}
|
||||
|
||||
public void run() throws FileNotFoundException, IOException {
|
||||
|
||||
@@ -47,7 +47,7 @@ class InitDatabase implements InitStep {
|
||||
this.ui = ui;
|
||||
this.site = site;
|
||||
this.libraries = libraries;
|
||||
this.database = sections.get("database");
|
||||
this.database = sections.get("database", null);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
@@ -31,7 +31,7 @@ class InitGitManager implements InitStep {
|
||||
@Inject
|
||||
InitGitManager(final ConsoleUI ui, final Section.Factory sections) {
|
||||
this.ui = ui;
|
||||
this.gerrit = sections.get("gerrit");
|
||||
this.gerrit = sections.get("gerrit", null);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
@@ -48,8 +48,8 @@ class InitHttpd implements InitStep {
|
||||
this.ui = ui;
|
||||
this.site = site;
|
||||
this.flags = flags;
|
||||
this.httpd = sections.get("httpd");
|
||||
this.gerrit = sections.get("gerrit");
|
||||
this.httpd = sections.get("httpd", null);
|
||||
this.gerrit = sections.get("gerrit", null);
|
||||
}
|
||||
|
||||
public void run() throws IOException, InterruptedException {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright (C) 2012 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.pgm.init;
|
||||
|
||||
import com.google.gerrit.extensions.annotations.PluginName;
|
||||
import com.google.gerrit.pgm.util.ConsoleUI;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
@Singleton
|
||||
public class InitPluginStepsLoader {
|
||||
private final File pluginsDir;
|
||||
private final Injector initInjector;
|
||||
final ConsoleUI ui;
|
||||
|
||||
@Inject
|
||||
public InitPluginStepsLoader(final ConsoleUI ui, final SitePaths sitePaths,
|
||||
final Injector initInjector) {
|
||||
this.pluginsDir = sitePaths.plugins_dir;
|
||||
this.initInjector = initInjector;
|
||||
this.ui = ui;
|
||||
}
|
||||
|
||||
public Collection<InitStep> getInitSteps() {
|
||||
List<File> jars = scanJarsInPluginsDirectory();
|
||||
ArrayList<InitStep> pluginsInitSteps = new ArrayList<InitStep>();
|
||||
|
||||
for (File jar : jars) {
|
||||
InitStep init = loadInitStep(jar);
|
||||
if (init != null) {
|
||||
pluginsInitSteps.add(init);
|
||||
}
|
||||
}
|
||||
return pluginsInitSteps;
|
||||
}
|
||||
|
||||
private InitStep loadInitStep(File jar) {
|
||||
try {
|
||||
ClassLoader pluginLoader =
|
||||
new URLClassLoader(new URL[] {jar.toURI().toURL()},
|
||||
InitPluginStepsLoader.class.getClassLoader());
|
||||
JarFile jarFile = new JarFile(jar);
|
||||
Attributes jarFileAttributes = jarFile.getManifest().getMainAttributes();
|
||||
String initClassName = jarFileAttributes.getValue("Gerrit-InitStep");
|
||||
if (initClassName == null) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends InitStep> initStepClass =
|
||||
(Class<? extends InitStep>) pluginLoader.loadClass(initClassName);
|
||||
return getPluginInjector(jar).getInstance(initStepClass);
|
||||
} catch (ClassCastException e) {
|
||||
ui.message(
|
||||
"WARN: InitStep from plugin %s does not implement %s (Exception: %s)",
|
||||
jar.getName(), InitStep.class.getName(), e.getMessage());
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
ui.message(
|
||||
"WARN: Cannot load and get plugin init step for %s (Exception: %s)",
|
||||
jar, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Injector getPluginInjector(File jarFile) {
|
||||
String jarFileName = jarFile.getName();
|
||||
final String pluginName =
|
||||
jarFileName.substring(0, jarFileName.lastIndexOf('.'));
|
||||
return initInjector.createChildInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(String.class).annotatedWith(PluginName.class).toInstance(
|
||||
pluginName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<File> scanJarsInPluginsDirectory() {
|
||||
if (pluginsDir == null || !pluginsDir.exists()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
File[] matches = pluginsDir.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
String n = pathname.getName();
|
||||
return (n.endsWith(".jar") && pathname.isFile());
|
||||
}
|
||||
});
|
||||
if (matches == null) {
|
||||
ui.message("WARN: Cannot list %s", pluginsDir.getAbsolutePath());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Arrays.sort(matches, new Comparator<File>() {
|
||||
@Override
|
||||
public int compare(File o1, File o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
return Arrays.asList(matches);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
@@ -39,17 +40,24 @@ public class InitPlugins implements InitStep {
|
||||
|
||||
private final ConsoleUI ui;
|
||||
private final SitePaths site;
|
||||
private InitPluginStepsLoader pluginLoader;
|
||||
|
||||
@Inject
|
||||
InitPlugins(final ConsoleUI ui, final SitePaths site) {
|
||||
InitPlugins(final ConsoleUI ui, final SitePaths site, InitPluginStepsLoader pluginLoader) {
|
||||
this.ui = ui;
|
||||
this.site = site;
|
||||
this.pluginLoader = pluginLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
ui.header("Plugins");
|
||||
|
||||
installPlugins();
|
||||
initPlugins();
|
||||
}
|
||||
|
||||
private void installPlugins() throws IOException {
|
||||
final File myWar;
|
||||
try {
|
||||
myWar = GerritLauncher.getDistributionArchive();
|
||||
@@ -127,6 +135,12 @@ public class InitPlugins implements InitStep {
|
||||
}
|
||||
}
|
||||
|
||||
private void initPlugins() throws Exception {
|
||||
for (InitStep initStep : pluginLoader.getInitSteps()) {
|
||||
initStep.run();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getVersion(final File plugin) throws IOException {
|
||||
final JarFile jarFile = new JarFile(plugin);
|
||||
try {
|
||||
|
||||
@@ -34,7 +34,7 @@ class InitSendEmail implements InitStep {
|
||||
InitSendEmail(final ConsoleUI ui, final SitePaths site,
|
||||
final Section.Factory sections) {
|
||||
this.ui = ui;
|
||||
this.sendemail = sections.get("sendemail");
|
||||
this.sendemail = sections.get("sendemail", null);
|
||||
this.site = site;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class InitSshd implements InitStep {
|
||||
this.ui = ui;
|
||||
this.site = site;
|
||||
this.libraries = libraries;
|
||||
this.sshd = sections.get("sshd");
|
||||
this.sshd = sections.get("sshd", null);
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
|
||||
@@ -25,52 +25,58 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Helper to edit a section of the configuration files. */
|
||||
class Section {
|
||||
interface Factory {
|
||||
Section get(String name);
|
||||
public class Section {
|
||||
public interface Factory {
|
||||
Section get(@Assisted("section") String section,
|
||||
@Assisted("subsection") String subsection);
|
||||
}
|
||||
|
||||
private final InitFlags flags;
|
||||
private final SitePaths site;
|
||||
private final ConsoleUI ui;
|
||||
private final String section;
|
||||
private final String subsection;
|
||||
|
||||
@Inject
|
||||
Section(final InitFlags flags, final SitePaths site, final ConsoleUI ui,
|
||||
@Assisted final String section) {
|
||||
public Section(final InitFlags flags, final SitePaths site,
|
||||
final ConsoleUI ui, @Assisted("section") final String section,
|
||||
@Assisted("subsection") @Nullable final String subsection) {
|
||||
this.flags = flags;
|
||||
this.site = site;
|
||||
this.ui = ui;
|
||||
this.section = section;
|
||||
this.subsection = subsection;
|
||||
}
|
||||
|
||||
String get(String name) {
|
||||
return flags.cfg.getString(section, null, name);
|
||||
}
|
||||
|
||||
void set(final String name, final String value) {
|
||||
public void set(final String name, final String value) {
|
||||
final ArrayList<String> all = new ArrayList<String>();
|
||||
all.addAll(Arrays.asList(flags.cfg.getStringList(section, null, name)));
|
||||
all.addAll(Arrays.asList(flags.cfg.getStringList(section, subsection, name)));
|
||||
|
||||
if (value != null) {
|
||||
if (all.size() == 0 || all.size() == 1) {
|
||||
flags.cfg.setString(section, null, name, value);
|
||||
flags.cfg.setString(section, subsection, name, value);
|
||||
} else {
|
||||
all.set(0, value);
|
||||
flags.cfg.setStringList(section, null, name, all);
|
||||
flags.cfg.setStringList(section, subsection, name, all);
|
||||
}
|
||||
|
||||
} else if (all.size() == 0) {
|
||||
} else if (all.size() == 1) {
|
||||
flags.cfg.unset(section, null, name);
|
||||
flags.cfg.unset(section, subsection, name);
|
||||
} else {
|
||||
all.remove(0);
|
||||
flags.cfg.setStringList(section, null, name, all);
|
||||
flags.cfg.setStringList(section, subsection, name, all);
|
||||
}
|
||||
}
|
||||
|
||||
<T extends Enum<?>> void set(final String name, final T value) {
|
||||
public <T extends Enum<?>> void set(final String name, final T value) {
|
||||
if (value != null) {
|
||||
set(name, value.name());
|
||||
} else {
|
||||
@@ -78,15 +84,15 @@ class Section {
|
||||
}
|
||||
}
|
||||
|
||||
void unset(String name) {
|
||||
public void unset(String name) {
|
||||
set(name, (String) null);
|
||||
}
|
||||
|
||||
String string(final String title, final String name, final String dv) {
|
||||
public String string(final String title, final String name, final String dv) {
|
||||
return string(title, name, dv, false);
|
||||
}
|
||||
|
||||
String string(final String title, final String name, final String dv,
|
||||
public String string(final String title, final String name, final String dv,
|
||||
final boolean nullIfDefault) {
|
||||
final String ov = get(name);
|
||||
String nv = ui.readString(ov != null ? ov : dv, "%s", title);
|
||||
@@ -99,19 +105,19 @@ class Section {
|
||||
return nv;
|
||||
}
|
||||
|
||||
File path(final String title, final String name, final String defValue) {
|
||||
public File path(final String title, final String name, final String defValue) {
|
||||
return site.resolve(string(title, name, defValue));
|
||||
}
|
||||
|
||||
<T extends Enum<?>> T select(final String title, final String name,
|
||||
public <T extends Enum<?>> T select(final String title, final String name,
|
||||
final T defValue) {
|
||||
return select(title, name, defValue, false);
|
||||
}
|
||||
|
||||
<T extends Enum<?>> T select(final String title, final String name,
|
||||
public <T extends Enum<?>> T select(final String title, final String name,
|
||||
final T defValue, final boolean nullIfDefault) {
|
||||
final boolean set = get(name) != null;
|
||||
T oldValue = ConfigUtil.getEnum(flags.cfg, section, null, name, defValue);
|
||||
T oldValue = ConfigUtil.getEnum(flags.cfg, section, subsection, name, defValue);
|
||||
T newValue = ui.readEnum(oldValue, "%s", title);
|
||||
if (nullIfDefault && newValue == defValue) {
|
||||
newValue = null;
|
||||
@@ -126,7 +132,7 @@ class Section {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
String select(final String title, final String name, final String dv,
|
||||
public String select(final String title, final String name, final String dv,
|
||||
Set<String> allowedValues) {
|
||||
final String ov = get(name);
|
||||
String nv = ui.readString(ov != null ? ov : dv, allowedValues, "%s", title);
|
||||
@@ -136,16 +142,16 @@ class Section {
|
||||
return nv;
|
||||
}
|
||||
|
||||
String password(final String username, final String password) {
|
||||
public String password(final String username, final String password) {
|
||||
final String ov = getSecure(password);
|
||||
|
||||
String user = flags.sec.getString(section, null, username);
|
||||
String user = flags.sec.getString(section, subsection, username);
|
||||
if (user == null) {
|
||||
user = get(username);
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
flags.sec.unset(section, null, password);
|
||||
flags.sec.unset(section, subsection, password);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -165,15 +171,15 @@ class Section {
|
||||
return nv;
|
||||
}
|
||||
|
||||
String getSecure(String name) {
|
||||
return flags.sec.getString(section, null, name);
|
||||
public String getSecure(String name) {
|
||||
return flags.sec.getString(section, subsection, name);
|
||||
}
|
||||
|
||||
void setSecure(String name, String value) {
|
||||
public void setSecure(String name, String value) {
|
||||
if (value != null) {
|
||||
flags.sec.setString(section, null, name, value);
|
||||
flags.sec.setString(section, subsection, name, value);
|
||||
} else {
|
||||
flags.sec.unset(section, null, name);
|
||||
flags.sec.unset(section, subsection, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class UpgradeFrom2_0_x implements InitStep {
|
||||
|
||||
final Properties oldprop = readGerritServerProperties();
|
||||
if (oldprop != null) {
|
||||
final Section database = sections.get("database");
|
||||
final Section database = sections.get("database", null);
|
||||
|
||||
String url = oldprop.getProperty("url");
|
||||
if (url != null && !convertUrl(database, url)) {
|
||||
|
||||
Reference in New Issue
Block a user