-
Jack MacLauchlan CS2015 authoredJack MacLauchlan CS2015 authored
IssueRepo.java 11.86 KiB
package git;
import issueData.Issue;
import issueData.User;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.MergeCommand;
import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.Merger;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefSpec;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.List;
public class IssueRepo {
private final ObjectInserter oi;
private Repository repository;
public IssueRepo() {
try {
this.repository = new FileRepositoryBuilder()
.setGitDir(new File("/home/jack/Documents/testrepo/.git"))
// .setGitDir(new File("/home/jack/Documents/testrepo2/.git"))
.build();
} catch (IOException e) {
e.printStackTrace();
}
oi = new ObjectInserter(repository);
}
public void push(String remote) {
try (Git git = new Git(repository)) {
try {
Iterable<PushResult> results = git.push().setRemote(remote).add("issues").call();
results.forEach(result -> result.getRemoteUpdates()
.forEach(remoteRefUpdate ->
System.out.println("Status - " + remoteRefUpdate.getStatus())));
} catch (GitAPIException e) {
e.printStackTrace();
}
}
}
public void pull(String remote) {
String clone = null;
try {
clone = localClone();
mergeOnClone(clone, remote);
} catch (IOException | GitAPIException e) {
e.printStackTrace();
} finally {
if (clone != null) {
try {
FileUtils.deleteDirectory(new File(clone));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void pullClone(String clone) throws IOException, GitAPIException {
try (Git git = new Git(repository)) {
StoredConfig config = git.getRepository().getConfig();
config.setString("remote", "remIssues", "url", clone);
config.save();
git.fetch().setRemote("remIssues")
.setRefSpecs(new RefSpec("refs/heads/issues:refs/remotes/remIssues"))
.call();
Ref localRef = repository.findRef("refs/heads/issues");
Ref remoteRef = repository.findRef("refs/remotes/remIssues");
RevCommit localCommit = null;
RevCommit remoteCommit = null;
try (RevWalk revWalk = new RevWalk(repository)) {
localCommit = revWalk.parseCommit(localRef.getObjectId());
remoteCommit = revWalk.parseCommit(remoteRef.getObjectId());
revWalk.dispose();
} catch (IOException e) {
e.printStackTrace();
}
Merger merger = MergeStrategy.THEIRS.newMerger(repository);
if (merger.merge(localCommit, remoteCommit)) {
String commit = "Merged " + localRef.getName() + " and " + remoteRef.getName();
commit(commit, merger.getResultTreeId(), localCommit, remoteCommit);
System.out.println("Issues pulled");
}
}
}
private String localClone() throws IOException, GitAPIException {
Path tempDir = Files.createTempDirectory("ddit");
tempDir.toFile().deleteOnExit();
Git.cloneRepository()
.setURI("/home/jack/Documents/testrepo/.git")
.setDirectory(tempDir.toFile())
.setBranchesToClone(Collections.singleton("refs/heads/issues"))
.setBranch("refs/heads/issues")
.call();
return tempDir.toString();
}
private void mergeOnClone(String clone, String remote) throws IOException, GitAPIException {
try (Git git = Git.open(new File(clone))) {
StoredConfig config = git.getRepository().getConfig();
config.setString("remote", "remIssues", "url", remote);
config.save();
git.fetch()
.setRemote("remIssues")
.setRefSpecs(new RefSpec("refs/heads/issues:refs/remotes/remIssues"))
.call();
ObjectId mergeBase = git.getRepository().resolve("remIssues");
MergeCommand merge = git.merge()
.include(mergeBase)
.setCommit(true)
.setMessage("Merged");
MergeResult mergeResult = merge.call();
System.out.println("attempting pullClone");
if (!mergeResult.getMergeStatus().isSuccessful() && mergeResult.getConflicts() != null) {
System.out.println("Conflicts exist in:");
mergeResult.getConflicts().forEach((k, v) -> System.out.println(k));
if (Desktop.isDesktopSupported()) {
List<Thread> threads = new ArrayList<>();
mergeResult.getConflicts().forEach((k, v) -> {
Runnable runnable = () -> {
try {
Desktop.getDesktop().open(new File(clone + "/" + k));
} catch (IOException e) {
e.printStackTrace();
}
};
Thread thread = new Thread(runnable);
threads.add(thread);
});
threads.forEach(Thread::start);
threads.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("Enter \"abort\" to stop pullClone or \"resolved\" if finished resolving - any other input will be treated as abort");
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
scanner.close();
if (input.equals("resolved")) {
git.add().addFilepattern(".").call();
git.commit().setMessage("resolved merge conflict").call();
pullClone(clone);
} else {
git.reset().setMode(ResetCommand.ResetType.HARD).call();
System.out.println("Merge abandoned");
}
}
} else if (mergeResult.getMergeStatus().isSuccessful()) {
pullClone(clone);
}
}
}
public void writeIssue(Issue issue, String commitMessage) throws IOException {
RevCommit currentCommit = getCurrentCommit();
IssueTreeBuilder issueWriter = new IssueTreeBuilder(repository);
issueWriter.buildIssueTree(issue);
List<Issue> sortedIssues = getIssues();
sortedIssues.add(issue);
sortedIssues.sort(Comparator.comparing(Issue::getOriginalHash));
TreeFormatter repoTreeFormatter = new TreeFormatter();
getTree(sortedIssues, repoTreeFormatter, issueWriter);
ObjectId repoTree = oi.insert(Constants.OBJ_TREE, repoTreeFormatter.toByteArray());
commit(commitMessage, repoTree, currentCommit);
}
public void updateIssues(Issue issue, String commitMessage) throws IOException {
RevCommit currentCommit = getCurrentCommit();
IssueTreeBuilder issueWriter = new IssueTreeBuilder(repository);
issueWriter.buildIssueTree(issue);
List<Issue> sortedIssues = getIssues();
sortedIssues.sort(Comparator.comparing(Issue::getOriginalHash));
int i = sortedIssues.indexOf(issue);
sortedIssues.remove(i);
sortedIssues.add(i, issue);
TreeFormatter repoTreeFormatter = new TreeFormatter();
getTree(sortedIssues, repoTreeFormatter, issueWriter);
ObjectId repoTree = oi.insert(Constants.OBJ_TREE, repoTreeFormatter.toByteArray());
commit(commitMessage, repoTree, currentCommit);
}
public void deleteIssue(String hash) throws IOException {
RevCommit currentCommit = getCurrentCommit();
List<Issue> sortedIssues = getIssues();
sortedIssues.sort(Comparator.comparing(Issue::getOriginalHash));
sortedIssues.removeIf(issue -> issue.getOriginalHash().equals(hash));
TreeFormatter repoTreeFormatter = new TreeFormatter();
IssueTreeBuilder issueWriter = new IssueTreeBuilder(repository);
getTree(sortedIssues, repoTreeFormatter, issueWriter);
ObjectId repoTree = oi.insert(Constants.OBJ_TREE, repoTreeFormatter.toByteArray());
commit("Deleted issue " + hash, repoTree, currentCommit);
}
private void getTree(List<Issue> sortedIssues, TreeFormatter repoTreeFormatter, IssueTreeBuilder issueWriter) {
sortedIssues.forEach(i -> {
try {
ObjectId issueObj = issueWriter.buildIssueTree(i);
repoTreeFormatter.append(i.getOriginalHash(), FileMode.TREE, issueObj);
} catch (IOException e) {
e.printStackTrace();
}
});
}
public List<Issue> getIssues() {
try {
IssueReader issueReader = new IssueReader(repository, getCurrentCommit().getTree());
return issueReader.getIssues();
} catch (IOException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
private void commit(String message, ObjectId tree, ObjectId... parent) throws IOException {
CommitBuilder commitBuilder = new CommitBuilder();
commitBuilder.setMessage(message);
PersonIdent personIdent = new PersonIdent(getUserName(), getUserEmail());
commitBuilder.setAuthor(personIdent);
commitBuilder.setCommitter(personIdent);
if (tree != null && parent != null) {
commitBuilder.setTreeId(tree);
commitBuilder.setParentIds(parent);
} else {
commitBuilder.setTreeId(oi.insert(Constants.OBJ_TREE, new byte[]{}));
}
//update issues branch ref to point to new commit
ObjectId newCommit = oi.insert(commitBuilder);
RevCommit commit;
try (RevWalk walk = new RevWalk(repository)) {
commit = walk.parseCommit(newCommit);
walk.dispose();
}
RefUpdate update = repository.updateRef("refs/heads/issues");
update.setNewObjectId(commit);
update.update();
}
public void commit(String message) throws IOException {
commit(message, null);
}
private RevCommit getCurrentCommit() throws IOException {
RevCommit commit;
Ref issueRef = repository.findRef("refs/heads/issues");
try (RevWalk walk = new RevWalk(repository)) {
commit = walk.parseCommit(issueRef.getObjectId());
walk.dispose();
return commit;
}
}
private String getUserName() {
String name = repository.getConfig().getString("user", null, "name");
return Objects.requireNonNullElse(name, "Username unknown ");
}
private String getUserEmail() {
String email = repository.getConfig().getString("user", null, "email");
return Objects.requireNonNullElse(email, "Email unknown");
}
public User getUser() {
return new User(getUserName(), getUserEmail());
}
}