svnserver.repository.git.push.GitPushNative.java Source code

Java tutorial

Introduction

Here is the source code for svnserver.repository.git.push.GitPushNative.java

Source

/**
 * This file is part of git-as-svn. It is subject to the license terms
 * in the LICENSE file found in the top-level directory of this distribution
 * and at http://www.gnu.org/licenses/gpl-2.0.html. No part of git-as-svn,
 * including this file, may be copied, modified, propagated, or distributed
 * except according to the terms contained in the LICENSE file.
 */
package svnserver.repository.git.push;

import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import svnserver.auth.User;
import svnserver.auth.UserDB;
import svnserver.context.LocalContext;
import svnserver.context.SharedContext;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
 * Git push by native git client.
 *
 * @author Artem V. Navrotskiy <bozaro@users.noreply.github.com>
 */
public class GitPushNative implements GitPusher {
    @NotNull
    private static final Logger log = LoggerFactory.getLogger(GitPushNativeConfig.class);
    @NotNull
    private static final String HOOK_MESSAGE_PREFIX = "remote:";
    @NotNull
    private static final String SYSTEM_MESSAGE_PREFIX = "!";

    @NotNull
    private final SharedContext context;

    public GitPushNative(@NotNull LocalContext context) {
        this.context = context.getShared();
    }

    @Override
    public boolean push(@NotNull Repository repository, @NotNull ObjectId commitId, @NotNull String branch,
            @NotNull User userInfo) throws SVNException, IOException {
        try {
            repository.getDirectory();
            final ProcessBuilder processBuilder = new ProcessBuilder("git", "push", "--porcelain", "--quiet", ".",
                    commitId.name() + ":" + branch).directory(repository.getDirectory()).redirectErrorStream(true);
            processBuilder.environment().put("LANG", "en_US.utf8");
            userInfo.updateEnvironment(processBuilder.environment());
            context.sure(UserDB.class).updateEnvironment(processBuilder.environment(), userInfo);
            final Process process = processBuilder.start();
            final StringBuilder resultBuilder = new StringBuilder();
            final StringBuilder hookBuilder = new StringBuilder();
            try (final BufferedReader stdout = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                while (true) {
                    final String line = stdout.readLine();
                    if (line == null) {
                        break;
                    }
                    if (line.startsWith(HOOK_MESSAGE_PREFIX)) {
                        if (hookBuilder.length() > 0)
                            hookBuilder.append('\n');
                        hookBuilder.append(line.substring(HOOK_MESSAGE_PREFIX.length() + 1));
                    }
                    if (line.startsWith(SYSTEM_MESSAGE_PREFIX)) {
                        // System message like:
                        // !   2d1ed4dcc45bef07f6dfffabe7d3ff53aa147705:refs/heads/local   [remote rejected] (pre-receive hook declined)
                        // !   75cad4dcb5f6982a1f2df073157f3aa2083ae272:refs/heads/local   [rejected] (non-fast-forward)
                        if (resultBuilder.length() > 0)
                            resultBuilder.append('\n');
                        resultBuilder.append(line.substring(SYSTEM_MESSAGE_PREFIX.length() + 1));
                    }
                }
            }
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                return true;
            }
            final String resultMessage = resultBuilder.toString();
            if (resultMessage.contains("non-fast-forward")) {
                return false;
            }
            if (resultMessage.contains("hook")) {
                final String hookMessage = hookBuilder.toString();
                log.warn("Push rejected by hook:\n{}", hookMessage);
                throw new SVNException(SVNErrorMessage.create(SVNErrorCode.REPOS_HOOK_FAILURE,
                        "Commit blocked by hook with output:\n" + hookMessage));
            }
            log.error("Unknown git push result:\n{}", resultMessage);
            throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_WRITE_ERROR, resultMessage));
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_WRITE_ERROR, e));
        }
    }
}