In-place diffs during push snapshot creation.

This commit is contained in:
Winston Li 2015-02-21 23:46:32 +00:00
parent ec13e184b7
commit fee792f5ee
17 changed files with 220 additions and 138 deletions

View file

@ -1,5 +1,7 @@
package uk.ac.ic.wlgitbridge.bridge;
import uk.ac.ic.wlgitbridge.writelatex.CandidateSnapshot;
/**
* Created by Winston on 16/11/14.
*/

View file

@ -5,7 +5,7 @@ import java.util.Map;
/**
* Created by Winston on 16/11/14.
*/
public interface RawDirectoryContents {
public interface RawDirectory {
public Map<String, byte[]> getFileContentsTable();
public Map<String, RawFile> getFileTable();
}

View file

@ -4,6 +4,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
/**
* Created by Winston on 16/11/14.
@ -22,4 +23,13 @@ public abstract class RawFile {
out.close();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RawFile)) {
return false;
}
RawFile that = (RawFile) obj;
return getPath().equals(that.getPath()) && Arrays.equals(getContents(), that.getContents());
}
}

View file

@ -3,7 +3,6 @@ package uk.ac.ic.wlgitbridge.bridge;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.UnexpectedPostbackException;
@ -23,7 +22,7 @@ public interface WriteLatexDataSource {
/* Called by request thread. */
public boolean repositoryExists(String projectName) throws ServiceMayNotContinueException;
public List<WritableRepositoryContents> getWritableRepositories(String projectName, Repository repository) throws IOException, SnapshotPostException;
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException, FailedConnectionException;
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectory directoryContents, RawDirectory oldDirectoryContents, String hostname) throws SnapshotPostException, IOException, FailedConnectionException;
void checkPostbackKey(String projectName, String postbackKey) throws InvalidPostbackKeyException;

View file

@ -6,7 +6,7 @@ import uk.ac.ic.wlgitbridge.writelatex.filestore.node.WLDirectoryNode;
/**
* Created by Winston on 16/11/14.
*/
public interface CandidateSnapshot {
public interface bullshit {
public JsonElement getJsonRepresentation();
public int getPreviousVersionID();

View file

@ -5,7 +5,7 @@ import org.eclipse.jgit.transport.PreReceiveHook;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.transport.ReceiveCommand.Result;
import org.eclipse.jgit.transport.ReceivePack;
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
import uk.ac.ic.wlgitbridge.bridge.RawDirectory;
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
import uk.ac.ic.wlgitbridge.git.handler.hook.exception.ForcedPushException;
import uk.ac.ic.wlgitbridge.git.handler.hook.exception.WrongBranchException;
@ -66,6 +66,7 @@ public class WriteLatexPutHook implements PreReceiveHook {
writeLatexDataSource.putDirectoryContentsToProjectWithName(repository.getWorkTree().getName(),
getPushedDirectoryContents(repository,
receiveCommand),
getOldDirectoryContents(repository),
hostname);
}
@ -81,10 +82,14 @@ public class WriteLatexPutHook implements PreReceiveHook {
}
}
private RawDirectoryContents getPushedDirectoryContents(Repository repository, ReceiveCommand receiveCommand) throws IOException {
private RawDirectory getPushedDirectoryContents(Repository repository, ReceiveCommand receiveCommand) throws IOException {
return new RepositoryObjectTreeWalker(repository,
receiveCommand.getNewId())
.getDirectoryContents();
}
private RawDirectory getOldDirectoryContents(Repository repository) throws IOException {
return new RepositoryObjectTreeWalker(repository).getDirectoryContents();
}
}

View file

@ -0,0 +1,24 @@
package uk.ac.ic.wlgitbridge.git.util;
import uk.ac.ic.wlgitbridge.bridge.RawDirectory;
import uk.ac.ic.wlgitbridge.bridge.RawFile;
import java.util.Map;
/**
* Created by Winston on 16/11/14.
*/
public class FileDirectory implements RawDirectory {
private final Map<String, RawFile> fileTable;
public FileDirectory(Map<String, RawFile> fileTable) {
this.fileTable = fileTable;
}
@Override
public Map<String, RawFile> getFileTable() {
return fileTable;
}
}

View file

@ -1,23 +0,0 @@
package uk.ac.ic.wlgitbridge.git.util;
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
import java.util.Map;
/**
* Created by Winston on 16/11/14.
*/
public class FileDirectoryContents implements RawDirectoryContents {
private final Map<String, byte[]> fileContentsTable;
public FileDirectoryContents(Map<String, byte[]> fileContentsTable) {
this.fileContentsTable = fileContentsTable;
}
@Override
public Map<String, byte[]> getFileContentsTable() {
return fileContentsTable;
}
}

View file

@ -4,7 +4,9 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
import uk.ac.ic.wlgitbridge.bridge.RawDirectory;
import uk.ac.ic.wlgitbridge.bridge.RawFile;
import uk.ac.ic.wlgitbridge.writelatex.filestore.RepositoryFile;
import java.io.IOException;
import java.util.HashMap;
@ -31,11 +33,14 @@ public class RepositoryObjectTreeWalker {
this(repository, repository.resolve("HEAD~" + fromHead));
}
public RawDirectoryContents getDirectoryContents() throws IOException {
return new FileDirectoryContents(walkGitObjectTree());
public RawDirectory getDirectoryContents() throws IOException {
return new FileDirectory(walkGitObjectTree());
}
private TreeWalk initTreeWalk(Repository repository, ObjectId objectId) throws IOException {
if (objectId == null) {
return null;
}
RevWalk walk = new RevWalk(repository);
TreeWalk treeWalk = new TreeWalk(repository);
treeWalk.addTree(walk.parseCommit(objectId).getTree());
@ -43,10 +48,14 @@ public class RepositoryObjectTreeWalker {
return treeWalk;
}
private Map<String, byte[]> walkGitObjectTree() throws IOException {
Map<String, byte[]> fileContentsTable = new HashMap<String, byte[]>();
private Map<String, RawFile> walkGitObjectTree() throws IOException {
Map<String, RawFile> fileContentsTable = new HashMap<String, RawFile>();
if (treeWalk == null) {
return fileContentsTable;
}
while (treeWalk.next()) {
fileContentsTable.put(treeWalk.getPathString(), repository.open(treeWalk.getObjectId(0)).getBytes());
String path = treeWalk.getPathString();
fileContentsTable.put(path, new RepositoryFile(path, repository.open(treeWalk.getObjectId(0)).getBytes()));
}
return fileContentsTable;
}

View file

@ -0,0 +1,104 @@
package uk.ac.ic.wlgitbridge.writelatex;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import uk.ac.ic.wlgitbridge.bridge.RawDirectory;
import uk.ac.ic.wlgitbridge.bridge.RawFile;
import uk.ac.ic.wlgitbridge.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Created by Winston on 16/11/14.
*/
public class CandidateSnapshot {
private final String projectName;
private final int currentVersion;
private final List<ServletFile> files;
public CandidateSnapshot(String projectName, int currentVersion, RawDirectory directoryContents, RawDirectory oldDirectoryContents) {
this.projectName = projectName;
this.currentVersion = currentVersion;
files = diff(directoryContents, oldDirectoryContents);
}
private List<ServletFile> diff(RawDirectory directoryContents, RawDirectory oldDirectoryContents) {
List<ServletFile> files = new LinkedList<ServletFile>();
Map<String, RawFile> fileTable = directoryContents.getFileTable();
Map<String, RawFile> oldFileTable = oldDirectoryContents.getFileTable();
for (Entry<String, RawFile> entry : fileTable.entrySet()) {
RawFile file = entry.getValue();
files.add(new ServletFile(file, oldFileTable.get(file.getPath())));
}
return files;
}
public void writeServletFiles(File rootGitDirectory) throws IOException {
File directory = new File(rootGitDirectory, ".wlgb/atts/" + projectName);
for (ServletFile file : files) {
if (file.isChanged()) {
file.writeToDisk(directory);
}
}
}
public JsonElement getJsonRepresentation(String postbackKey) {
String projectURL = Util.getPostbackURL() + projectName;
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("latestVerId", currentVersion);
jsonObject.add("files", getFilesAsJson(projectURL, postbackKey));
jsonObject.addProperty("postbackUrl", projectURL + "/" + postbackKey + "/postback");
return jsonObject;
}
private JsonArray getFilesAsJson(String projectURL, String postbackKey) {
JsonArray filesArray = new JsonArray();
for (ServletFile file : files) {
filesArray.add(getFileAsJson(file, projectURL, postbackKey));
}
return filesArray;
}
private JsonObject getFileAsJson(ServletFile file, String projectURL, String postbackKey) {
JsonObject jsonFile = new JsonObject();
jsonFile.addProperty("name", file.getPath());
if (file.isChanged()) {
jsonFile.addProperty("url", projectURL + "/" + file.getPath() + "?key=" + postbackKey);
}
return jsonFile;
}
public String getProjectName() {
return projectName;
}
// @Override
// public int getPreviousVersionID() {
// return previousVersionID;
// }
//
// @Override
// public String getProjectURL() {
// return projectURL;
// }
//
// @Override
// public void approveWithVersionID(int versionID) {
// callback.approveSnapshot(versionID, this);
// }
//
//
// @Override
// public WLDirectoryNode getDirectoryNode() {
// return directoryNode;
// }
}

View file

@ -0,0 +1,32 @@
package uk.ac.ic.wlgitbridge.writelatex;
import uk.ac.ic.wlgitbridge.bridge.RawFile;
/**
* Created by Winston on 21/02/15.
*/
public class ServletFile extends RawFile {
private final RawFile file;
private final boolean changed;
public ServletFile(RawFile file, RawFile oldFile) {
this.file = file;
changed = equals(oldFile);
}
@Override
public String getPath() {
return file.getPath();
}
@Override
public byte[] getContents() {
return file.getContents();
}
public boolean isChanged() {
return changed;
}
}

View file

@ -1,80 +0,0 @@
package uk.ac.ic.wlgitbridge.writelatex;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* Created by Winston on 16/11/14.
*/
public class WLDirectoryNodeSnapshot /*implements CandidateSnapshot*/ {
// private final int previousVersionID;
// private final String projectName;
// private final String projectURL;
// private final WLDirectoryNode directoryNode;
// private final String postbackKey;
// private final CandidateSnapshotCallback callback;
// public WLDirectoryNodeSnapshot(WLProject project, WLDirectoryNode directoryNode, String hostname, String postbackKey, CandidateSnapshotCallback callback) {
// previousVersionID = project.getLatestSnapshotID();
// projectName = project.getName();
// projectURL = Util.getPostbackURL() + projectName;
//
// this.directoryNode = directoryNode;
// this.postbackKey = postbackKey;
// this.callback = callback;
// }
// @Override
public JsonElement getJsonRepresentation() {
JsonObject jsonObject = new JsonObject();
// jsonObject.addProperty("latestVerId", previousVersionID);
// jsonObject.add("files", getFilesAsJson());
// jsonObject.addProperty("postbackUrl", projectURL + "/" + postbackKey + "/postback");
return jsonObject;
}
private JsonArray getFilesAsJson() {
JsonArray filesArray = new JsonArray();
// for (FileNode fileNode : directoryNode.getFileNodes()) {
// filesArray.add(getFileAsJson(fileNode));
// }
return filesArray;
}
// private JsonObject getFileAsJson(FileNode fileNode) {
// JsonObject file = new JsonObject();
// file.addProperty("name", fileNode.getFilePath());
// if (fileNode.isChanged()) {
// file.addProperty("url", projectURL + "/" + fileNode.getFilePath() + "?key=" + postbackKey);
// }
// return file;
// }
// @Override
// public int getPreviousVersionID() {
// return previousVersionID;
// }
//
// @Override
// public String getProjectURL() {
// return projectURL;
// }
//
// @Override
// public void approveWithVersionID(int versionID) {
// callback.approveSnapshot(versionID, this);
// }
//
// @Override
// public String getProjectName() {
// return projectName;
// }
//
// @Override
// public WLDirectoryNode getDirectoryNode() {
// return directoryNode;
// }
}

View file

@ -2,8 +2,7 @@ package uk.ac.ic.wlgitbridge.writelatex;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
import uk.ac.ic.wlgitbridge.bridge.RawDirectory;
import uk.ac.ic.wlgitbridge.bridge.WritableRepositoryContents;
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
import uk.ac.ic.wlgitbridge.util.Util;
@ -72,17 +71,17 @@ public class WriteLatexAPI implements WriteLatexDataSource {
}
@Override
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException {
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectory directoryContents, RawDirectory oldDirectoryContents, String hostname) throws SnapshotPostException, IOException {
mainProjectLock.lockForProject(projectName);
try {
Util.sout("Pushing project: " + projectName);
String postbackKey = postbackManager.makeKeyForProject(projectName);
CandidateSnapshot candidate = dataModel.createCandidateSnapshotFromProjectWithContents(projectName, directoryContents, hostname, postbackKey);
SnapshotPushRequest snapshotPushRequest = new SnapshotPushRequest(candidate);
CandidateSnapshot candidate = dataModel.createCandidateSnapshotFromProjectWithContents(projectName, directoryContents, oldDirectoryContents);
SnapshotPushRequest snapshotPushRequest = new SnapshotPushRequest(candidate, postbackKey);
snapshotPushRequest.request();
SnapshotPushRequestResult result = snapshotPushRequest.getResult();
if (result.wasSuccessful()) {
candidate.approveWithVersionID(postbackManager.getVersionID(projectName));
dataModel.approveSnapshot(postbackManager.getVersionID(projectName), candidate);
} else {
throw new OutOfDateException();
}

View file

@ -1,7 +1,7 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
import uk.ac.ic.wlgitbridge.writelatex.CandidateSnapshot;
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.HTTPMethod;
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.SnapshotAPIRequest;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
@ -14,10 +14,12 @@ public class SnapshotPushRequest extends SnapshotAPIRequest<SnapshotPushRequestR
private static final String API_CALL = "/snapshots";
private final CandidateSnapshot candidateSnapshot;
private final String postbackKey;
public SnapshotPushRequest(CandidateSnapshot candidateSnapshot) {
public SnapshotPushRequest(CandidateSnapshot candidateSnapshot, String postbackKey) {
super(candidateSnapshot.getProjectName(), API_CALL);
this.candidateSnapshot = candidateSnapshot;
this.postbackKey = postbackKey;
}
@Override
@ -27,7 +29,7 @@ public class SnapshotPushRequest extends SnapshotAPIRequest<SnapshotPushRequestR
@Override
protected String getPostBody() {
return candidateSnapshot.getJsonRepresentation().toString();
return candidateSnapshot.getJsonRepresentation(postbackKey).toString();
}
@Override

View file

@ -1,6 +1,6 @@
package uk.ac.ic.wlgitbridge.writelatex.filestore.store;
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
import uk.ac.ic.wlgitbridge.bridge.bullshit;
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.WLDirectoryNode;
import java.io.File;
@ -73,7 +73,7 @@ public class WLFileStore /*implements PersistentStoreSource*/ {
// return getDirectoryNodeForProjectName(project.getName()).createFromRawDirectoryContents(directoryContents, attDirectory);
// }
public void approveCandidateSnapshot(CandidateSnapshot candidateSnapshot) {
public void approveCandidateSnapshot(bullshit candidateSnapshot) {
WLDirectoryNode directoryNode = candidateSnapshot.getDirectoryNode();
fileStore.put(candidateSnapshot.getProjectName(), directoryNode);
// directoryNode.updatePersistentStore(persistentStore, null);

View file

@ -3,6 +3,7 @@ package uk.ac.ic.wlgitbridge.writelatex.model;
import org.eclipse.jgit.lib.Repository;
import uk.ac.ic.wlgitbridge.bridge.*;
import uk.ac.ic.wlgitbridge.writelatex.SnapshotFetcher;
import uk.ac.ic.wlgitbridge.writelatex.CandidateSnapshot;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotAttachment;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
@ -55,20 +56,18 @@ public class DataStore implements CandidateSnapshotCallback {
return commits;
}
public CandidateSnapshot createCandidateSnapshotFromProjectWithContents(String projectName, RawDirectoryContents directoryContents, String hostname, String postbackKey) throws SnapshotPostException, IOException, FailedConnectionException {
// return new WLDirectoryNodeSnapshot(getProjectWithName(projectName),
// fileStore.createNextDirectoryNodeInProjectFromContents(getProjectWithName(projectName),
// directoryContents),
// hostname,
// postbackKey,
// this);
return null;
public CandidateSnapshot createCandidateSnapshotFromProjectWithContents(String projectName, RawDirectory directoryContents, RawDirectory oldDirectoryContents) throws SnapshotPostException, IOException, FailedConnectionException {
CandidateSnapshot candidateSnapshot = new CandidateSnapshot(projectName,
persistentStore.getLatestVersionForProject(projectName),
directoryContents,
oldDirectoryContents);
candidateSnapshot.writeServletFiles(rootGitDirectory);
return candidateSnapshot;
}
@Override
public void approveSnapshot(int versionID, CandidateSnapshot candidateSnapshot) {
// getProjectWithName(candidateSnapshot.getProjectName()).putLatestSnapshot(versionID);
// fileStore.approveCandidateSnapshot(candidateSnapshot);
persistentStore.setLatestVersionForProject(candidateSnapshot.getProjectName(), versionID);
}
private File initRootGitDirectory(String rootGitDirectoryPath) {

View file

@ -32,7 +32,7 @@ public class ResourceFetcher {
path = newPath;
contents = fetch(projectName, url, path);
} else {
contents = new RepositoryObjectTreeWalker(repository).getDirectoryContents().getFileContentsTable().get(path);
contents = new RepositoryObjectTreeWalker(repository).getDirectoryContents().getFileTable().get(path).getContents();
}
return new RepositoryFile(path, contents);
}