Package core plugins in Gerrit war and install them on init

This change adds a new Maven project 'gerrit-package-plugins' which
adds the core plugin jars to the Gerrit war file. Inside of the
resulting Gerrit war file the plugins are stored under
'WEB-INF/plugins/'.

The init command will now look at this folder during the site
initialization and offer the plugins for installation.

Change-Id: Ia6c28ef13bbbb7a0358c84e785b8422a2e6a47b3
This commit is contained in:
Edwin Kempin 2012-07-23 10:46:06 +02:00
parent 88531176ec
commit 67e09dc69e
9 changed files with 307 additions and 30 deletions

View File

@ -1,11 +1,11 @@
Making a Gerrit Sub Project Release
===================================
Making a Release of a Gerrit Subproject / Core Plugin
=====================================================
Preparing a New Gerrit Subproject Snapshot for Publishing
---------------------------------------------------------
Preparing a New Snapshot for Publishing
---------------------------------------
* You will need to have the following in the pom.xml to make it
deployable to the gerrit-maven storage bucket:
* You will need to have the following in the `pom.xml` to make it
deployable to the `gerrit-maven` storage bucket:
----
<distributionManagement>
@ -19,7 +19,7 @@ Preparing a New Gerrit Subproject Snapshot for Publishing
----
* Add this to the pom.xml to enable the wagon provider:
* Add this to the `pom.xml` to enable the wagon provider:
----
<build>
@ -34,7 +34,7 @@ Preparing a New Gerrit Subproject Snapshot for Publishing
----
* Add your username and password to your ~/.m2/settings.xml file.
* Add your username and password to your `~/.m2/settings.xml` file.
These need to come from the link:https://code.google.com/apis/console/[API Console].
----
@ -52,11 +52,14 @@ Preparing a New Gerrit Subproject Snapshot for Publishing
----
Making a Gerrit Subproject Snapshot
-----------------------------------
Making a Snapshot
-----------------
* First build and deploy the latest snapshot and ensure that Gerrit builds
with this snapshot
* Only for plugins: in the `pom.xml` update the Gerrit version under
`properties` > `Gerrit-ApiVersion` to the version of the new Gerrit
release
* First build and deploy the latest snapshot and ensure that Gerrit
builds/runs with this snapshot
* Deploy the snapshot:
@ -65,15 +68,17 @@ with this snapshot
====
Making a Gerrit Subproject Release
----------------------------------
Making a Release
----------------
* First deploy (and test) the latest snapshot for the subproject
* First deploy (and test) the latest snapshot for the subproject/plugin
* Update the top level pom.xml in the subproject to reflect the new project
version (the exact value of the tag you will create below)
* Update the top level `pom.xml` in the subproject/plugin to reflect
the new project version (the exact value of the tag you will create
below)
* Commit the pom change and push to the project's repo refs/for/<master/stable>
* Commit the pom change and push to the project's repo
`refs/for/<master/stable>`
* Tag the version you just pushed (and push the tag)

View File

@ -78,16 +78,19 @@ Prepare the Subprojects
Prepare Gerrit
~~~~~~~~~~~~~~
* In the 'stable-2.5' branch: Update the top level pom in Gerrit to ensure that
none of the Subprojects point to snapshot releases
* Create a `stable-2.5` branch for making the new release
* In the 'master' branch: Update the poms for the Gerrit version, push for
* In the `master` branch: Update the poms for the Gerrit version, push for
review, get merged
====
tools/version.sh --snapshot=2.5
====
* Checkout the `stable-2.5` branch
* Update the top level `pom.xml` in Gerrit to ensure that none of the
Subprojects point to snapshot releases
* Tag
====
@ -95,14 +98,35 @@ review, get merged
git tag -a -m "gerrit 2.5" v2.5
====
* Build
* Build (without plugins)
====
./tools/release.sh
====
* Sanity check WAR
Publish the Plugin API JAR File
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Push JAR to `commondatastorage.googleapis.com`
** Run `tools/deploy_api.sh`
Prepare the Core Plugins
~~~~~~~~~~~~~~~~~~~~~~~~
* link:dev-release-subproject.html[Release and publish] the core plugins
Package Gerrit with Plugins
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Ensure that the core plugins listed in `gerrit-package-plugins/pom.xml`
point to the latest release version (no dependency to snapshot versions)
* Include core plugins into WAR
====
$ ./tools/version.sh --release && mvn clean package -f gerrit-package-plugins/pom.xml
$ ./tools/version.sh --reset
====
* Find WAR that includes the core plugins at
`gerrit-package-plugins\target\gerrit-v2.5.war`
* Sanity check WAR
Publish to the Project Locations
--------------------------------
@ -118,12 +142,6 @@ WAR File
** new war: [release-candidate], featured...
** old war: deprecated
Plugin API JAR File
~~~~~~~~~~~~~~~~~~~
* Push JAR to commondatastorage.googleapis.com
** Run tools/deploy_api.sh
Tag
~~~

6
gerrit-package-plugins/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/target
/.classpath
/.project
/.settings/org.maven.ide.eclipse.prefs
/.settings/org.eclipse.m2e.core.prefs
/gerrit-package-plugins.iml

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-package-plugins</artifactId>
<packaging>war</packaging>
<version>2.5-SNAPSHOT</version>
<name>Gerrit Code Review - Package Plugins</name>
<url>http://code.google.com/p/gerrit/</url>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-war</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.googlesource.gerrit.plugins.replication</groupId>
<artifactId>replication</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeTypes>jar</includeTypes>
<stripVersion>true</stripVersion>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/plugins</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<warName>gerrit-${project.version}</warName>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifestEntries>
<Main-Class>Main</Main-Class>
<Implementation-Title>Gerrit Code Review</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -43,6 +43,7 @@ public class InitModule extends FactoryModule {
step().to(InitSshd.class);
step().to(InitHttpd.class);
step().to(InitCache.class);
step().to(InitPlugins.class);
}
protected LinkedBindingBuilder<InitStep> step() {

View File

@ -0,0 +1,140 @@
// 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.launcher.GerritLauncher;
import com.google.gerrit.pgm.util.ConsoleUI;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@Singleton
public class InitPlugins implements InitStep {
private final static String PLUGIN_DIR = "WEB-INF/plugins/";
private final static String JAR = ".jar";
private final ConsoleUI ui;
private final SitePaths site;
@Inject
InitPlugins(final ConsoleUI ui, final SitePaths site) {
this.ui = ui;
this.site = site;
}
@Override
public void run() throws Exception {
ui.header("Plugins");
final File myWar;
try {
myWar = GerritLauncher.getDistributionArchive();
} catch (FileNotFoundException e) {
System.err.println("warn: Cannot find gerrit.war");
return;
}
boolean foundPlugin = false;
try {
final ZipFile zf = new ZipFile(myWar);
try {
final Enumeration<? extends ZipEntry> e = zf.entries();
while (e.hasMoreElements()) {
final ZipEntry ze = e.nextElement();
if (ze.isDirectory()) {
continue;
}
if (ze.getName().startsWith(PLUGIN_DIR) && ze.getName().endsWith(JAR)) {
if (!foundPlugin) {
if (!ui.yesno(false, "Prompt to install core plugins")) {
return;
}
foundPlugin = true;
}
final String pluginJarName = new File(ze.getName()).getName();
final String pluginName = pluginJarName.substring(0, pluginJarName.length() - JAR.length());
final InputStream in = zf.getInputStream(ze);
try {
final File tmpPlugin = PluginLoader.storeInTemp(pluginName, in, site);
final String pluginVersion = getVersion(tmpPlugin);
if (!ui.yesno(false, "Install plugin %s version %s", pluginName,
pluginVersion)) {
tmpPlugin.delete();
continue;
}
final File plugin = new File(site.plugins_dir, pluginJarName);
if (plugin.exists()) {
final String installedPluginVersion = getVersion(plugin);
if (!ui.yesno(false,
"version %s is already installed, overwrite it",
installedPluginVersion)) {
tmpPlugin.delete();
continue;
}
if (!plugin.delete()) {
throw new IOException("Failed to delete plugin " + pluginName
+ ": " + plugin.getAbsolutePath());
}
}
if (!tmpPlugin.renameTo(plugin)) {
throw new IOException("Failed to install plugin " + pluginName
+ ": " + tmpPlugin.getAbsolutePath() + " -> "
+ plugin.getAbsolutePath());
}
} finally {
in.close();
}
}
}
} finally {
zf.close();
}
} catch (IOException e) {
throw new IOException("Failure during plugin installation", e);
}
if (!foundPlugin) {
ui.message("No plugins found.");
}
}
private static String getVersion(final File plugin) throws IOException {
final JarFile jarFile = new JarFile(plugin);
try {
final Manifest manifest = jarFile.getManifest();
final Attributes main = manifest.getMainAttributes();
return main.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
} finally {
jarFile.close();
}
}
}

View File

@ -61,6 +61,9 @@ public abstract class ConsoleUI {
/** Display a header message before a series of prompts. */
public abstract void header(String fmt, Object... args);
/** Display a message. */
public abstract void message(String fmt, Object... args);
/** Request the user to answer a yes/no question. */
public abstract boolean yesno(Boolean def, String fmt, Object... args);
@ -215,6 +218,11 @@ public abstract class ConsoleUI {
fmt = fmt.replaceAll("\n", "\n*** ");
console.printf("\n*** " + fmt + "\n*** \n\n", args);
}
@Override
public void message(String fmt, Object... args) {
console.printf(fmt, args);
}
}
private static class Batch extends ConsoleUI {
@ -250,5 +258,9 @@ public abstract class ConsoleUI {
@Override
public void header(String fmt, Object... args) {
}
@Override
public void message(String fmt, Object... args) {
}
}
}

View File

@ -148,6 +148,11 @@ public class PluginLoader implements LifecycleListener {
}
}
public static File storeInTemp(String pluginName, InputStream in,
SitePaths sitePaths) throws IOException {
return asTemp(in, tempNameFor(pluginName), ".jar", sitePaths.tmp_dir);
}
private static File asTemp(InputStream in,
String prefix, String suffix,
File dir) throws IOException {

View File

@ -25,7 +25,7 @@ then
fi
./tools/version.sh --release &&
mvn clean package $include_docs -P all
mvn clean install $include_docs -P all
rc=$?
./tools/version.sh --reset