Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add interface to configure details of JGit's pack implementation #617

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/git.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ sshd.setCommandFactory(new GitPackCommandFactory().withGitLocationResolver(resol

```

To further control what happens in response to `git-receive-pack` and `git-upload-pack`, you can implement a `GitPackConfiguration` which will be used
to configure JGit's `ReceivePack` and `UploadPack`, respectively:

```java
sshd.setCommandFactory(new GitPackCommandFactory()
.withGitPackConfiguration(new GitPackConfiguration() {
@Override
public void configureReceivePack(ServerSession session, ReceivePack pack) {
pack.setPreReceiveHook(...);
// ...
}

@Override
public void configureUploadPack(ServerSession session, UploadPack pack) {
pack.setRefFilter(...);
// ...
}
}));
```

These command factories also accept a delegate to which non-_git_ commands are routed:

```java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class GitPackCommand extends AbstractGitCommand {

private GitPackConfiguration packConfiguration = GitPackConfiguration.NOTHING;

/**
* @param rootDirResolver Resolver for GIT root directory
* @param command Command to execute
Expand All @@ -61,7 +64,7 @@ public void run() {
String command = getCommand();
try {
List<String> strs = parseDelimitedString(command, " ", true);
String[] args = strs.toArray(new String[strs.size()]);
String[] args = strs.toArray(new String[0]);
for (int i = 0; i < args.length; i++) {
String argVal = args[i];
if (argVal.startsWith("'") && argVal.endsWith("'")) {
Expand All @@ -83,6 +86,7 @@ public void run() {
String subCommand = args[0];
if (RemoteConfig.DEFAULT_UPLOAD_PACK.equals(subCommand)) {
UploadPack uploadPack = new UploadPack(db);
packConfiguration.configureUploadPack(getSession(), uploadPack);
Environment environment = getEnvironment();
Map<String, String> envVars = environment.getEnv();
String protocol = MapEntryUtils.isEmpty(envVars)
Expand All @@ -92,7 +96,9 @@ public void run() {
}
uploadPack.upload(getInputStream(), getOutputStream(), getErrorStream());
} else if (RemoteConfig.DEFAULT_RECEIVE_PACK.equals(subCommand)) {
new ReceivePack(db).receive(getInputStream(), getOutputStream(), getErrorStream());
ReceivePack receivePack = new ReceivePack(db);
packConfiguration.configureReceivePack(getSession(), receivePack);
receivePack.receive(getInputStream(), getOutputStream(), getErrorStream());
} else {
throw new IllegalArgumentException("Unknown git command: " + command);
}
Expand All @@ -118,4 +124,9 @@ protected Path resolveRootDirectory(String command, String[] args) throws IOExce
ValidateUtils.checkNotNullAndNotEmpty(pathArg, "No %s command sub-path specified", args[0]);
return rootDir.resolve(pathArg);
}

public void setPackConfiguration(GitPackConfiguration packConfiguration) {
this.packConfiguration = ValidateUtils.checkNotNull(packConfiguration,
"Pack configuration must not be null");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class GitPackCommandFactory extends AbstractGitCommandFactory {
public static final String GIT_FACTORY_NAME = "git-pack";
public static final String GIT_COMMAND_PREFIX = "git-";

private GitPackConfiguration packConfiguration;

public GitPackCommandFactory() {
this(null);
}
Expand Down Expand Up @@ -61,6 +63,25 @@ public GitPackCommandFactory withExecutorServiceProvider(

@Override
public GitPackCommand createGitCommand(String command) {
return new GitPackCommand(getGitLocationResolver(), command, resolveExecutorService(command));
GitPackCommand cmd = new GitPackCommand(getGitLocationResolver(), command, resolveExecutorService(command));
if (packConfiguration != null) {
cmd.setPackConfiguration(packConfiguration);
}
return cmd;
}

/**
* Sets the {@link GitPackConfiguration} that will be set for all {@link GitPackCommand}s created by this factory.
* <p>
* Every time a {@link GitPackCommand} creates a JGit {@code UploadPack} or {@code ReceivePack}, the corresponding
* method of the {@link GitPackConfiguration} set here is called. This allows you to configure JGit further, e.g. to
* set pre- and post-receive hooks.
*
* @param configuration the configuration to use for git pack commands.
* @return Self instance
*/
public GitPackCommandFactory withGitPackConfiguration(GitPackConfiguration configuration) {
this.packConfiguration = configuration;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sshd.git.pack;

import org.apache.sshd.server.session.ServerSession;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.UploadPack;

/**
* Interface specifying methods that can be used to configure JGit's pack objects.
*/
public interface GitPackConfiguration {

GitPackConfiguration NOTHING = new GitPackConfiguration() {
};

default void configureReceivePack(ServerSession session, ReceivePack pack) {
// Nothing by default
}

default void configureUploadPack(ServerSession session, UploadPack pack) {
// Nothing by default
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.apache.sshd.git.transport.GitSshdSessionFactory;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.password.AcceptAllPasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.sftp.server.SftpSubsystemFactory;
import org.apache.sshd.util.test.BaseTestSupport;
import org.apache.sshd.util.test.CommonTestSupportUtils;
Expand All @@ -40,7 +41,9 @@
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.GitProtocolConstants;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.UploadPack;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -77,9 +80,11 @@ void gitPack() throws Exception {

Path gitRootDir = getTempTargetRelativeFile(getClass().getSimpleName());
try (SshServer sshd = setupTestServer()) {
GitPackTestConfig packConfig = new GitPackTestConfig();
Path serverRootDir = gitRootDir.resolve("server");
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
sshd.setCommandFactory(new GitPackCommandFactory(GitLocationResolver.constantPath(serverRootDir)));
sshd.setCommandFactory(new GitPackCommandFactory(GitLocationResolver.constantPath(serverRootDir))
.withGitPackConfiguration(packConfig));
sshd.start();

int port = sshd.getPort();
Expand Down Expand Up @@ -124,6 +129,9 @@ void gitPack() throws Exception {
git.fetch().call();
assertTrue(client.isStarted(),
"Client not started after fetch using GIT_PROTOCOL='version=2' env. variable");

assertTrue(packConfig.receivePackCalled, "ReceivePack was not configured");
assertTrue(packConfig.uploadPackCalled, "UploadPack was not configured");
} finally {
client.stop();
}
Expand All @@ -134,4 +142,19 @@ void gitPack() throws Exception {
}
}
}

private static class GitPackTestConfig implements GitPackConfiguration {
boolean receivePackCalled;
boolean uploadPackCalled;

@Override
public void configureReceivePack(ServerSession session, ReceivePack pack) {
receivePackCalled = true;
}

@Override
public void configureUploadPack(ServerSession session, UploadPack pack) {
uploadPackCalled = true;
}
}
}