io.github.svndump_to_git.git.utils.ExternalGitUtils Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2014 The Kuali Foundation Licensed under the
* Educational Community 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.osedu.org/licenses/ECL-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 io.github.svndump_to_git.git.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.transport.ReceiveCommand.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author ocleirig
*
*/
public final class ExternalGitUtils {
private static final Logger log = LoggerFactory
.getLogger(ExternalGitUtils.class);
/**
*
*/
private ExternalGitUtils() {
// TODO Auto-generated constructor stub
}
/**
* Use CGit to fetch the specified remote name from the indicated repository.
*
* @param externalCGitCommandPath path to C git binary
* @param repo git repository
* @param remoteName the name of the remote specified in the repositories git configuration file.
* @param depth if < 1 then apply no limit if >e; 1 then specify with the --depth option for a shallow checkout.
* @param redirectStream output stream needed by waitFor
*
* @return true if the fetch worked
*/
public static boolean fetch (String externalCGitCommandPath, Repository repo, String remoteName, int depth, OutputStream redirectStream) {
try {
ListcommandArgs = new ArrayList();
commandArgs.add("fetch");
commandArgs.add(remoteName);
if (depth >= 1) {
commandArgs.add("--depth=" + depth);
}
Process p = runGitCommand(externalCGitCommandPath, repo, true, commandArgs.toArray(new String[] {}));
waitFor(p, redirectStream);
return true;
} catch (IOException e) {
return false;
} catch (InterruptedException e) {
return false;
}
}
public static boolean applyPatch (String externalGitCommandPath, Repository repo, InputStream patchStream, OutputStream redirectStream) {
try {
/*
* First read the patchStream into a temporary file
*/
File tempFile = File.createTempFile("patch", "dat");
tempFile.deleteOnExit();
int totalCopied = IOUtils.copy(patchStream, new FileOutputStream(tempFile));
log.debug("copied " + totalCopied + " bytes into " + tempFile.getAbsolutePath());
ListcommandArgs = new ArrayList();
commandArgs.add("apply");
commandArgs.add(tempFile.getAbsolutePath());
Process p = runGitCommand(externalGitCommandPath, repo, false, commandArgs.toArray(new String[] {}));
waitFor(p, redirectStream);
return true;
} catch (IOException e) {
return false;
} catch (InterruptedException e) {
return false;
}
}
/**
* Use CGit to fetch all of the remotes defined in the projects git configuration.
*
* @param externalGitCommandPath
* @param repo
* @param depth if < 1 then apply no limit if >e; then specify with the --depth option for a shallow checkout.
* @param redirectStream
*
* @return
*/
public static boolean fetchAll (String externalGitCommandPath, Repository repo, int depth, OutputStream redirectStream) {
try {
ListcommandArgs = new ArrayList();
commandArgs.add("fetch");
commandArgs.add("--all");
if (depth >= 1) {
commandArgs.add("--depth=" + depth);
}
Process p = runGitCommand(externalGitCommandPath, repo, true, commandArgs.toArray(new String[] {}));
waitFor(p, redirectStream);
return true;
} catch (IOException e) {
return false;
} catch (InterruptedException e) {
return false;
}
}
/**
* Checkout the named branch using the branch name provided.
*
* @param externalGitCommandPath
* @param repo
* @param branchName
* @param redirectStream
* if not null then output from the sub process will be written
* here.
* @return
*/
public static boolean checkoutBranch(String externalGitCommandPath,
Repository repo, String branchName, boolean force,
OutputStream redirectStream) {
try {
Process p = null;
if (force) {
p = runGitCommand(externalGitCommandPath, repo, false,
"checkout", branchName, "--force");
} else {
p = runGitCommand(externalGitCommandPath, repo, false,
"checkout", branchName);
}
int result = waitFor(p, redirectStream);
if (result == 0)
return true;
else {
readStream(p.getErrorStream(), redirectStream);
return false;
}
} catch (IOException e) {
log.error("failed to checkout branch", e);
return false;
} catch (InterruptedException e) {
return false;
}
}
// set inGitMetaDirectory to false to run in the working copy directory.
private static Process runGitCommand(String externalGitCommandPath,
Repository repo, boolean inGitMetaDirectory,
String... gitCommandArgs) throws IOException {
List commandArgs = new ArrayList<>();
commandArgs.add(externalGitCommandPath);
commandArgs.addAll(Arrays.asList(gitCommandArgs));
return runGitCommand(repo, inGitMetaDirectory, commandArgs);
}
private static Process runGitCommand(Repository repo,
boolean inGitMetaDirectory, List commandArgs)
throws IOException {
File gitDirectory = null;
if (inGitMetaDirectory)
gitDirectory = repo.getDirectory();
else
gitDirectory = repo.getWorkTree();
// inherit the parent environment
// locate in the working copy of the gir directory
Process p = Runtime.getRuntime().exec(
commandArgs.toArray(new String[] {}), null, gitDirectory);
return p;
}
private static int waitFor(Process p, OutputStream redirectStream)
throws InterruptedException, IOException {
if (redirectStream != null) {
readStream(p.getInputStream(), redirectStream);
}
return p.waitFor();
}
private static void readStream(InputStream inputStream,
OutputStream redirectStream) throws IOException {
BufferedReader outReader = new BufferedReader(new InputStreamReader(
inputStream));
while (true) {
String errorLine = outReader.readLine();
if (errorLine == null)
break;
redirectStream.write(errorLine.getBytes());
redirectStream.write("\n".getBytes());
}
}
public static boolean runGarbageCollection(String externalGitCommandPath,
Repository repo, OutputStream redirectStream) {
try {
Process p = runGitCommand(externalGitCommandPath, repo, true, "gc");
waitFor(p, redirectStream);
return true;
} catch (IOException e) {
return false;
} catch (InterruptedException e) {
return false;
}
}
public static boolean updateRef(String externalGitCommand, Repository repo,
String absoluteRefName, ObjectId objectId, boolean force,
OutputStream redirectStream) throws IOException {
List commandOptions = new ArrayList<>();
commandOptions.add("branch");
if (force)
commandOptions.add("-f");
commandOptions.add(absoluteRefName);
commandOptions.add(objectId.getName());
try {
Process p = runGitCommand(repo, true, commandOptions);
waitFor(p, redirectStream);
if (p.exitValue() == 0)
return true;
else
return false;
} catch (InterruptedException e) {
}
return false;
}
/**
* Run the batch ref updates using the external git command instead of the
* JGit command.
*
* @param externalGitCommand
* @param repo
* @param deferredReferenceDeletes
* @param redirectStream
* @throws IOException
*/
public static void batchRefUpdate(String externalGitCommand,
Repository repo, List deferredReferenceDeletes,
OutputStream redirectStream) throws IOException {
for (ReceiveCommand receiveCommand : deferredReferenceDeletes) {
String[] parts = receiveCommand.getRefName().split("/");
String refName = parts[parts.length - 1];
ObjectId refObjectId = receiveCommand.getNewId();
List commandOptions = new ArrayList<>();
commandOptions.add(externalGitCommand);
switch (receiveCommand.getType()) {
case CREATE:
commandOptions.add("branch");
commandOptions.add(refName);
commandOptions.add(refObjectId.getName());
break;
case DELETE:
commandOptions.add("branch");
commandOptions.add("-D");
commandOptions.add(refName);
break;
case UPDATE:
case UPDATE_NONFASTFORWARD:
commandOptions.add("branch");
commandOptions.add("-f");
commandOptions.add(refName);
commandOptions.add(refObjectId.getName());
break;
}
try {
Process p = runGitCommand(repo, true, commandOptions);
waitFor(p, redirectStream);
if (p.exitValue() == 0) {
// normal termination
if (receiveCommand.getType().equals(Type.CREATE)) {
// C git doesn't say anything in this case so log it
redirectStream.write(("Created branch " + receiveCommand.getRefName() + "\n").getBytes());
}
}
} catch (InterruptedException e) {
}
}
}
/**
* Setup the Credential Helper to point at a file configured with the credentials.
*
* Each line in the file is in the format of: https://user:[email protected]
*
* @param externalCGitCommand
* @param tempFile
* @throws IOException
*/
public static void setupLocalCredentialHelper(String externalCGitCommand, Repository repo, File tempFile) throws IOException {
// assuming this is a non-bare repo
runGitCommand(externalCGitCommand, repo, false, "config", "--local", "credential.helper", "store --file=" + tempFile.getAbsolutePath());
}
/**
* Remove any configured Credential Helper Section from the local git repository.
* @param externalCGitCommand
* @param repo
* @throws IOException
*/
public static void cleanupLocalCredentialHelper(String externalCGitCommand, Repository repo) throws IOException {
// assuming this is a non-bare repo
runGitCommand(externalCGitCommand, repo, false, "config", "--local", "--remove-section", "credential");
}
/**
* Push the refspec given to the remote given.
*
* @param externalGitCommandPath
* @param repo
* @param refSpec
* @param remoteName
* @throws IOException
*/
public static void push (String externalGitCommandPath, Repository repo, String refSpec, String remoteName) throws IOException {
runGitCommand(externalGitCommandPath, repo, false, "push", remoteName, refSpec);
}
}