From ec85a070b36afdf7eb2c1247a7d2f5ff4c7f692c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1a=20=C5=BDivkov?= Date: Tue, 28 Jan 2014 10:08:25 +0100 Subject: [PATCH] Add extension point for receive-pack initialization. Plugins can register ReceivePackInitializer's in order to provide custom initialization of the ReceivePack instance. For example, the quota plugin may use this extension point to set the maximum allowed pack size based on its quota configuration and the disk space occupied by that project. Change-Id: I8d6e7d4bb75099b0fa5f6968ae5371883bf865ee --- Documentation/dev-plugins.txt | 8 +++++ .../gerrit/httpd/GitOverHttpServlet.java | 14 +++++++- .../server/config/GerritGlobalModule.java | 1 + .../server/config/ReceivePackInitializer.java | 36 +++++++++++++++++++ .../google/gerrit/sshd/commands/Receive.java | 12 +++++++ 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/config/ReceivePackInitializer.java diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt index 296c42e43c..14470b085f 100644 --- a/Documentation/dev-plugins.txt +++ b/Documentation/dev-plugins.txt @@ -416,6 +416,14 @@ its own custom event class derived from `ChangeEvent`. Certain operations in Gerrit can be validated by plugins by implementing the corresponding link:config-validation.html[listeners]. +[[receive-pack]] +== Receive Pack Initializers + +Plugins may provide ReceivePack initializers which will be invoked +by Gerrit just before a ReceivePack instance will be used. Usually, +plugins will make use of the setXXX methods on the ReceivePack to +set additional properties on it. + [[ssh]] == SSH Commands diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java index 4ecd020a96..b40b1fa39b 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java @@ -16,6 +16,7 @@ package com.google.gerrit.httpd; import com.google.common.cache.Cache; import com.google.gerrit.common.data.Capable; +import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.AccessPath; @@ -23,6 +24,7 @@ import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.cache.CacheModule; +import com.google.gerrit.server.config.ReceivePackInitializer; import com.google.gerrit.server.git.AsyncReceiveCommits; import com.google.gerrit.server.git.ChangeCache; import com.google.gerrit.server.git.GitRepositoryManager; @@ -244,11 +246,14 @@ public class GitOverHttpServlet extends GitServlet { static class ReceiveFactory implements ReceivePackFactory { private final AsyncReceiveCommits.Factory factory; private final TransferConfig config; + private DynamicSet receivePackInitializers; @Inject - ReceiveFactory(AsyncReceiveCommits.Factory factory, TransferConfig config) { + ReceiveFactory(AsyncReceiveCommits.Factory factory, TransferConfig config, + DynamicSet receivePackInitializers) { this.factory = factory; this.config = config; + this.receivePackInitializers = receivePackInitializers; } @Override @@ -267,9 +272,16 @@ public class GitOverHttpServlet extends GitServlet { rp.setRefLogIdent(user.newRefLogIdent()); rp.setTimeout(config.getTimeout()); rp.setMaxObjectSizeLimit(config.getMaxObjectSizeLimit()); + init(pc.getProject().getNameKey(), rp); req.setAttribute(ATT_RC, rc); return rp; } + + private void init(Project.NameKey project, ReceivePack rp) { + for (ReceivePackInitializer initializer : receivePackInitializers) { + initializer.init(project, rp); + } + } } static class ReceiveFilter implements Filter { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java index aa772f9add..73f6bf76bf 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java @@ -243,6 +243,7 @@ public class GerritGlobalModule extends FactoryModule { DynamicSet.setOf(binder(), CacheRemovalListener.class); DynamicMap.mapOf(binder(), CapabilityDefinition.class); DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class); + DynamicSet.setOf(binder(), ReceivePackInitializer.class); DynamicSet.setOf(binder(), NewProjectCreatedListener.class); DynamicSet.setOf(binder(), ProjectDeletedListener.class); DynamicSet.setOf(binder(), HeadUpdatedListener.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ReceivePackInitializer.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ReceivePackInitializer.java new file mode 100644 index 0000000000..cfc384d69b --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ReceivePackInitializer.java @@ -0,0 +1,36 @@ +// 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.config; + +import com.google.gerrit.extensions.annotations.ExtensionPoint; +import com.google.gerrit.reviewdb.client.Project; + +import org.eclipse.jgit.transport.ReceivePack; + +@ExtensionPoint +public interface ReceivePackInitializer { + + /** + * ReceivePack initialization. + * + * Invoked by Gerrit when a new ReceivePack instance is created and just + * before it is used. Implementors will usually call setXXX methods on the + * receivePack parameter in order to set additional properties on it. + * + * @param project project for which the ReceivePack is created + * @param receivePack the ReceivePack instance which is being initialized + */ + public void init(Project.NameKey project, ReceivePack receivePack); +} diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java index 92444f45a8..6c8af21de4 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java @@ -15,8 +15,10 @@ package com.google.gerrit.sshd.commands; import com.google.gerrit.common.data.Capable; +import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.config.ReceivePackInitializer; import com.google.gerrit.server.git.AsyncReceiveCommits; import com.google.gerrit.server.git.ReceiveCommits; import com.google.gerrit.server.git.TransferConfig; @@ -59,6 +61,9 @@ final class Receive extends AbstractGitCommand { @Inject private TransferConfig config; + @Inject + private DynamicSet receivePackInitializers; + private final Set reviewerId = new HashSet(); private final Set ccId = new HashSet(); @@ -97,6 +102,7 @@ final class Receive extends AbstractGitCommand { rp.setTimeout(config.getTimeout()); rp.setMaxObjectSizeLimit(config.getEffectiveMaxObjectSizeLimit( projectControl.getProjectState())); + init(rp); try { rp.receive(in, out, err); } catch (UnpackException badStream) { @@ -163,6 +169,12 @@ final class Receive extends AbstractGitCommand { } } + private void init(ReceivePack rp) { + for (ReceivePackInitializer initializer : receivePackInitializers) { + initializer.init(projectControl.getProject().getNameKey(), rp); + } + } + private void verifyProjectVisible(final String type, final Set who) throws UnloggedFailure { for (final Account.Id id : who) {