package org.kohsuke.github; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.MoreObjects; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; public class BlazarGHRepository extends GHRepository { private final int id; private static final Logger LOG = LoggerFactory.getLogger(BlazarGHRepository.class); private final String name; private final String fullName; private Map<String, ? extends GHBranch> branches; private BlazarGHUser owner; private List<BlazarGHCommit> commits; private final BlazarGHTree tree; private String host; private List<BlazarGHChange> history; @JsonCreator public BlazarGHRepository(@JsonProperty("name") String name, @JsonProperty("id") int id, @JsonProperty("commits") List<BlazarGHCommit> commits, @JsonProperty("branches") Map<String, BlazarGHBranch> branches, @JsonProperty("tree") BlazarGHTree tree, @JsonProperty("owner") BlazarGHUser owner) throws IOException { this.id = id; this.name = name; this.owner = owner; this.commits = commits; for (BlazarGHBranch b : branches.values()) { b.setRepository(this); } for (BlazarGHCommit c : commits) { c.setRepository(this); } this.branches = branches; this.tree = tree; this.fullName = String.format("%s/%s", owner.getLogin(), name); this.history = new ArrayList<>(); } @Override public int getId() { return id; } @Override public String getName() { return name; } @Override public String getFullName() { return fullName; } @Override public String getOwnerName() { return owner.getLogin(); } @Override public BlazarGHUser getOwner() { return owner; } public void setOwner(BlazarGHUser user) { owner = user; } @Override public GHTree getTreeRecursive(String gitBranchName, int recursive) throws IOException { // So far in Blazar we only call this with branch name, afaict it can be any gitRef + int if (branches.keySet().contains(gitBranchName)) { String sha1 = branches.get(gitBranchName).getSHA1(); // find the point in the tree that has the sha we're looking for // tree is really a misnomer... this is a list. :shrug: that's the ghe api for you for (GHTreeEntry entry : tree.getTree()) { if (entry.getSha().equals(sha1)) { int index = tree.getTree().indexOf(entry); return new BlazarGHTree(sha1, tree.getSubclassTree().subList(index, tree.getTree().size())); } } throw new IllegalArgumentException(String.format("The sha %s for branch %s points to a sha which doesn't exist in our tree", sha1, gitBranchName)); } throw new IllegalArgumentException(String.format("Branch %s doesn't exist", gitBranchName)); } @Override public Map<String, GHBranch> getBranches() throws IOException { return (Map<String, GHBranch>) this.branches; } @Override public GHCommit getCommit(String sha1) throws IOException { for (BlazarGHCommit c : commits) { if (c.getSHA1().equals(sha1)) { return c; } } throw new IllegalArgumentException("No commit with that sha in this repo"); } @Override public GHCompare getCompare(String id1, String id2) throws IOException { List<String> shas = new ArrayList<>(); for (BlazarGHCommit commit : commits) { shas.add(commit.getSHA1()); } // because the "newer" sha (id2) will be first in the shas list // we flip the indicies in the sublist call, to ensure the sublist isn't backwards int index1 = shas.indexOf(id1); int index2 = shas.indexOf(id2); List<BlazarGHCommit> compareListWrongType = commits.subList(index2, index1); List<BlazarGHCompare.Commit> compareList = new ArrayList<>(); for (BlazarGHCommit commit : compareListWrongType) { compareList.add(BlazarGHCompare.makeCommit(commit)); } BlazarGHCompare.Commit commitArray[] = new BlazarGHCompare.Commit[compareList.size()]; return new BlazarGHCompare(compareList.toArray(commitArray)); } @Override public URL getHtmlUrl() { try { return new URL("https", host, String.format("/%s/%s", owner.getLogin(), name)); } catch (MalformedURLException e) { throw new RuntimeException(e); } } @Override public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException { return createCommitStatus(sha1, state, targetUrl, description, "Blazar"); } @Override public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, String context) throws IOException { LOG.info("Faking commit status creation {sha={} state={} message='{}' context={}}", sha1.substring(0, 8), state.toString(), description, context); return null; } @Override public GHContent getFileContent(String path, String ref) throws IOException { if (branches.containsKey(ref)) { BlazarGHTree tree = (BlazarGHTree) getTreeRecursive(ref, 1); for (BlazarGHTreeEntry entry : tree.getSubclassTree()) { if (entry.getPath().equals(path)) { return entry.getContent(); } } throw new FileNotFoundException(String.format("No such file %s", path)); } for (BlazarGHTreeEntry entry : tree.getSubclassTree()) { if (entry.getSha().equals(ref)) { return entry.getContent(); } } throw new IllegalArgumentException(String.format("No such ref %s", ref)); } public void setHost(String host) { this.host = host; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("name", fullName).toString(); } public void applyChange(BlazarGHChange change) throws IOException { history.add(0, change); commits.add(0, change.getCommit()); commits.get(0).setRepository(this); change.setOldCommitSha1(Optional.of(tree.getSha())); change.setOldEntries(Optional.<List<BlazarGHTreeEntry>>of(ImmutableList.copyOf(tree.getSubclassTree()))); // point branch HEAD to new commit Map<String, BlazarGHBranch> newBranches = new HashMap<>(); newBranches.putAll((Map<String, BlazarGHBranch>) branches); newBranches.put(change.getBranch(), new BlazarGHBranch(change.getBranch(), change.getCommit().getSHA1())); branches = newBranches; // mutate tree List<BlazarGHTreeEntry> newEntries = new ArrayList<>(); newEntries.addAll(change.getEntries()); newEntries.addAll(tree.getSubclassTree()); newBranches.get(change.getBranch()).setRepository(this); tree.set(change.getCommit().getSHA1(), newEntries); } public void revertLastChange() throws IOException { if (history.size() <= 0) { throw new UnsupportedOperationException("Cannot pop commit from empty history"); } BlazarGHChange change = history.remove(0); if (!change.getOldEntries().isPresent() || !change.getOldCommitSha1().isPresent()) { throw new IllegalStateException("Change found in repo history with no old data to restore to"); } commits.remove(0); tree.set(change.getOldCommitSha1().get(), change.getOldEntries().get()); // change head back Map<String, BlazarGHBranch> newBranches = new HashMap<>(); newBranches.putAll((Map<String, BlazarGHBranch>) branches); newBranches.put(change.getBranch(), new BlazarGHBranch(change.getBranch(), change.getOldCommitSha1().get())); newBranches.get(change.getBranch()).setRepository(this); branches = newBranches; } }