package org.tmatesoft.svn.core.test; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.util.SVNStreamGobbler; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.util.SVNLogType; import java.io.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class GitRepositoryAccess { private final File workingTree; private final String gitCommand; public GitRepositoryAccess(File workingTree, String gitCommand) { this.workingTree = workingTree; this.gitCommand = gitCommand; } public void deleteDotGitDirectory() throws SVNException { SVNFileUtil.deleteAll(getDotGitDirectory(), true, null); } public File getWorkingTree() { return workingTree; } public File getDotGitDirectory() { return new File(workingTree, ".git"); } public void init() throws SVNException { runGit("init", "."); } public void performImport(String commitMessage) throws SVNException { runGit("add", "."); runGit("commit", "-m", commitMessage); } public String getCommitMessage(GitObjectId commitId) throws SVNException { final String output = runGit("cat-file", "commit", commitId.asString()); final String[] lines = output.split("\n"); final StringBuilder commitMessageBuilder = new StringBuilder(); boolean emptyLineFound = false; for (String line : lines) { line = line.trim(); if (line.length() == 0) { emptyLineFound = true; continue; } if (!emptyLineFound) { continue; } //this line belongs to a commit message commitMessageBuilder.append(line).append('\n'); } return commitMessageBuilder.toString().trim(); } public GitObjectId getBlobId(GitObjectId treeish, String relativePath) throws SVNException { final String output = runGit("ls-tree", "-r", treeish.asString(), relativePath).trim(); if (output.length() == 0) { return null; } return new GitObjectId(output.split(" ")[2].split("\t")[0].trim()); } public void copyBlobToFile(GitObjectId blobId, File outputFile) throws SVNException { runGitRedirectOutput(outputFile, "cat-file", "blob", blobId.asString()); } public GitObjectId getHeadId() throws SVNException { final String output = runGit("rev-parse", "HEAD"); return new GitObjectId(output.trim()); } public List<GitObjectId> getCommitsByFirstParent(GitObjectId fromCommitId) throws SVNException { final String output = runGit("rev-list", "--first-parent", fromCommitId.asString()); return parseCommitsList(output); } public List<GitObjectId> getCommitsByFirstParentUntil(GitObjectId fromCommitId, GitObjectId toCommitIdExcluding) throws SVNException { final String output = runGit("rev-list", "--first-parent", fromCommitId.asString(), "^" + toCommitIdExcluding); return parseCommitsList(output); } private String runGit(String... args) throws SVNException { List<String> command = new ArrayList<String>(1 + (args == null ? 0 : args.length)); command.add(gitCommand); if (args != null) { Collections.addAll(command, args); } ProcessBuilder processBuilder = new ProcessBuilder(command); processBuilder.directory(workingTree); SVNStreamGobbler inputGobbler = null; SVNStreamGobbler errorGobbler = null; try { Process process = processBuilder.start(); inputGobbler = new SVNStreamGobbler(process.getInputStream()); errorGobbler = new SVNStreamGobbler(process.getErrorStream()); inputGobbler.start(); errorGobbler.start(); process.waitFor(); inputGobbler.waitFor(); errorGobbler.waitFor(); } catch (IOException e) { SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e); SVNErrorManager.error(errorMessage, SVNLogType.WC); } catch (InterruptedException e) { SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e); SVNErrorManager.error(errorMessage, SVNLogType.WC); } finally { if (inputGobbler != null) { inputGobbler.close(); } if (errorGobbler != null) { errorGobbler.close(); } } return inputGobbler.getResult(); } private void runGitRedirectOutput(File outputFile, String... args) throws SVNException { List<String> command = new ArrayList<String>(1 + (args == null ? 0 : args.length)); command.add(gitCommand); if (args != null) { Collections.addAll(command, args); } ProcessBuilder processBuilder = new ProcessBuilder(command); processBuilder.directory(workingTree); SVNBinaryStreamGobbler inputGobbler = null; try { Process process = processBuilder.start(); inputGobbler = new SVNBinaryStreamGobbler(process.getInputStream(), new BufferedOutputStream(new FileOutputStream(outputFile))); inputGobbler.start(); process.waitFor(); inputGobbler.waitFor(); } catch (IOException e) { SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e); SVNErrorManager.error(errorMessage, SVNLogType.WC); } catch (InterruptedException e) { SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e); SVNErrorManager.error(errorMessage, SVNLogType.WC); } finally { if (inputGobbler != null) { inputGobbler.close(); } } } private List<GitObjectId> parseCommitsList(String output) { final String[] lines = output.split("\n"); final List<GitObjectId> commits = new ArrayList<GitObjectId>(lines.length); for (String line : lines) { line = line.trim(); if (line.length() == 0) { continue; } commits.add(new GitObjectId(line)); } return commits; } private static class SVNBinaryStreamGobbler extends Thread { private IOException error; private boolean myIsEOF; private boolean myIsClosed; private final InputStream inputStream; private final OutputStream outputStream; public SVNBinaryStreamGobbler(InputStream inputStream, OutputStream outputStream) { this.inputStream = inputStream; this.outputStream = outputStream; } public void run() { byte[] buffer = new byte[1024]; synchronized (outputStream) { while (true) { try { int r = inputStream.read(buffer); if (r < 0) { break; } if (r > 0) { outputStream.write(buffer, 0, r); } } catch (IOException e) { if (!myIsClosed) { error = e; } break; } } myIsEOF = true; outputStream.notifyAll(); } } public void waitFor() { synchronized (outputStream) { while (!myIsEOF) { try { outputStream.wait(); } catch (InterruptedException e) { } } } } public void close() { synchronized (outputStream) { myIsEOF = true; outputStream.notifyAll(); myIsClosed = true; SVNFileUtil.closeFile(inputStream); SVNFileUtil.closeFile(outputStream); } } public IOException getError() { return error; } } }