com.metaeffekt.artifact.analysis.utils.GitAccess Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2021-2024 the original author or authors.
*
* 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.metaeffekt.artifact.analysis.utils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class GitAccess {
private static final Logger LOG = LoggerFactory.getLogger(GitAccess.class);
private String proxyScheme;
private String proxyHost;
private String proxyUsername;
private String proxyPassword;
private Integer proxyPort;
private GIT_COMMAND_PROXY_SET_TYPE gitCommandProxySetType = GIT_COMMAND_PROXY_SET_TYPE.ENVIRONMENT;
public enum GIT_COMMAND_PROXY_SET_TYPE {
ENVIRONMENT,
PARAMETERS
}
public GitAccess(String proxyScheme, String proxyHost, Integer proxyPort, String proxyUsername, String proxyPassword) {
this.setProxyConfig(proxyScheme, proxyHost, proxyPort, proxyUsername, proxyPassword);
}
public GitAccess(String proxyScheme, String proxyHost, Integer proxyPort) {
this.setProxyConfig(proxyScheme, proxyHost, proxyPort, null, null);
}
public GitAccess() {
this.setProxyConfig(null, null, null, null, null);
}
public void setProxyConfig(String proxyScheme, String proxyHost, Integer proxyPort, String proxyUsername, String proxyPassword) {
this.proxyScheme = proxyScheme;
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
this.proxyUsername = proxyUsername;
this.proxyPassword = proxyPassword;
}
public void setGitCommandProxySetType(GIT_COMMAND_PROXY_SET_TYPE gitCommandProxySetType) {
this.gitCommandProxySetType = gitCommandProxySetType;
}
public void cloneRemote(File targetDir, String remote, String branch) throws IOException {
// only shallow clone
final String[] gitClone = new String[]{"git", "clone", "--depth", "1", remote, targetDir.getAbsolutePath()};
executeCommand(gitClone, null);
if (branch != null) {
checkout(targetDir, branch);
}
}
public void pull(File targetDir) throws IOException {
final String[] gitPull = new String[]{"git", "pull"};
executeCommand(gitPull, targetDir);
}
public void fetch(File targetDir) throws IOException {
final String[] gitFetch = new String[]{"git", "fetch"};
executeCommand(gitFetch, targetDir);
}
public void checkout(File targetDir, String branchOrTag) throws IOException {
final String[] gitCheckout = new String[]{"git", "checkout", branchOrTag};
executeCommand(gitCheckout, targetDir);
}
public void push(File targetDir) throws IOException {
final String[] gitPush = new String[]{"git", "push"};
executeCommand(gitPush, targetDir);
}
public List listBranches(File targetDir) throws IOException {
final String[] gitBranch = new String[]{"git", "branch", "-r"};
return executeCommandAndCollectOutput(gitBranch, targetDir).stream()
.filter(b -> !b.contains(" -> "))
.map(String::trim)
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
}
public List listTags(File targetDir) throws IOException {
final String[] gitTag = new String[]{"git", "tag"};
return executeCommandAndCollectOutput(gitTag, targetDir).stream()
.map(String::trim)
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
}
private ProcessBuilder buildProcess(final String[] command, final File targetDir) {
final List modifiedCommand = new ArrayList<>(Arrays.asList(command));
final boolean hasProxy = proxyScheme != null && proxyHost != null && proxyPort != null;
final boolean hasAnyProxy = hasProxy || (proxyUsername != null && proxyPassword != null);
if (hasAnyProxy != hasProxy) {
LOG.warn("Incomplete proxy configuration in git command, will still try to execute command");
}
final ProcessBuilder processBuilder = new ProcessBuilder(modifiedCommand);
if (targetDir != null) {
if (targetDir.exists()) {
processBuilder.directory(targetDir.getAbsoluteFile());
} else {
throw new IllegalStateException("Target directory does not exist: " + targetDir.getAbsolutePath());
}
}
if (hasProxy) {
final String proxyCredentials = proxyUsername != null && proxyPassword != null
? proxyUsername + ":" + proxyPassword + "@"
: "";
final String proxySetting = proxyScheme + "://" + proxyCredentials + proxyHost + ":" + proxyPort;
LOG.info("Using [GIT_COMMAND_PROXY_SET_TYPE.{}] to configure git proxy", gitCommandProxySetType);
if (gitCommandProxySetType == GIT_COMMAND_PROXY_SET_TYPE.ENVIRONMENT) {
processBuilder.environment().put("HTTP_PROXY", proxySetting);
processBuilder.environment().put("http_proxy", proxySetting);
processBuilder.environment().put("HTTPS_PROXY", proxySetting);
processBuilder.environment().put("https_proxy", proxySetting);
} else if (gitCommandProxySetType == GIT_COMMAND_PROXY_SET_TYPE.PARAMETERS) {
int gitIndex = modifiedCommand.indexOf("git");
if (gitIndex != -1) {
modifiedCommand.add(gitIndex + 1, "-c");
modifiedCommand.add(gitIndex + 2, "http.proxy=" + proxySetting);
}
} else {
throw new IllegalStateException("Unsupported proxy set type: " + gitCommandProxySetType);
}
}
if (targetDir != null) {
LOG.info("git command [{}]: {}", targetDir.getName(), String.join(" ", modifiedCommand));
} else {
LOG.info("git command: {}", String.join(" ", modifiedCommand));
}
return processBuilder;
}
private void executeCommand(final String[] command, final File targetDir) throws IOException {
final ProcessBuilder processBuilder = buildProcess(command, targetDir);
final Process p = processBuilder.start();
final StringBuilder outputBuilder = new StringBuilder();
final StringBuilder errorBuilder = new StringBuilder();
// capture output stream
final BufferedReader outputReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = outputReader.readLine()) != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("[stdout] {}", line);
} else {
outputBuilder.append(line).append("\n");
}
}
// capture error stream
final BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = errorReader.readLine()) != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("[stderr] {}", line);
} else {
errorBuilder.append(line).append("\n");
}
}
waitForProcess(p);
if (p.exitValue() != 0) {
if (LOG.isDebugEnabled()) {
throw new IllegalStateException("Command failed. Exit code: " + p.exitValue());
} else {
throw new IllegalStateException("Command failed. Exit code: " + p.exitValue() + "\nOutput:\n" + outputBuilder + "\n\nError:\n" + errorBuilder);
}
}
}
private List executeCommandAndCollectOutput(String[] command, File targetDir) throws IOException {
final ProcessBuilder processBuilder = buildProcess(command, targetDir);
final Process p = processBuilder.start();
final StringBuilder outputBuilder = new StringBuilder();
final StringBuilder errorBuilder = new StringBuilder();
// capture output stream
try (BufferedReader outputReader = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while ((line = outputReader.readLine()) != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("[stdout] {}", line);
}
outputBuilder.append(line).append("\n");
}
}
// capture error stream
try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String line;
while ((line = errorReader.readLine()) != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("[stderr] {}", line);
} else {
errorBuilder.append(line).append("\n");
}
}
}
waitForProcess(p);
if (p.exitValue() != 0) {
if (LOG.isDebugEnabled()) {
throw new IllegalStateException("Command failed. Exit code: " + p.exitValue());
} else {
throw new IllegalStateException("Command failed. Exit code: " + p.exitValue() + "\nOutput:\n" + outputBuilder + "\n\nError:\n" + errorBuilder);
}
}
final List output = new ArrayList<>();
for (String s : outputBuilder.toString().split("\n")) {
output.add(s.trim());
}
return output;
}
private void waitForProcess(Process p) {
try {
while (p.isAlive()) {
p.waitFor(1000, TimeUnit.MILLISECONDS);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
IOUtils.copy(p.getInputStream(), baos);
} catch (IOException e) {
LOG.error("Unable to copy input stream into output stream.", e);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy