use of org.locationtech.geogig.api.plumbing.WriteTree2 in project GeoGig by boundlessgeo.
the class IndexTest method testWriteTree.
@Test
public void testWriteTree() throws Exception {
insertAndAdd(points1);
insertAndAdd(lines1);
// this new root tree must exist on the repo db, but is not set as the current head. In
// fact, it is headless, as there's no commit pointing to it. CommitOp does that.
ObjectId newRootTreeId = geogig.command(WriteTree.class).setOldRoot(tree(repo.getHead().get().getObjectId())).call();
assertNotNull(newRootTreeId);
assertFalse(repo.getRootTreeId().equals(newRootTreeId));
// but the index staged root shall be pointing to it
// assertEquals(newRootTreeId, index.getStaged().getId());
RevTree tree = repo.getTree(newRootTreeId);
// assertEquals(2, tree.size().intValue());
String path = appendChild(pointsName, points1.getIdentifier().getID());
assertTrue(repo.command(FindTreeChild.class).setParent(tree).setChildPath(path).call().isPresent());
path = appendChild(linesName, lines1.getIdentifier().getID());
assertTrue(repo.command(FindTreeChild.class).setParent(tree).setChildPath(path).call().isPresent());
// simulate a commit so the repo head points to this new tree
ObjectInserter objectInserter = repo.newObjectInserter();
List<ObjectId> parents = ImmutableList.of();
RevCommit commit = new CommitBuilder(geogig.getPlatform()).setTreeId(newRootTreeId).setParentIds(parents).build();
ObjectId commitId = commit.getId();
objectInserter.insert(commit);
Optional<Ref> newHead = geogig.command(UpdateRef.class).setName("refs/heads/master").setNewValue(commitId).call();
assertTrue(newHead.isPresent());
WorkingTree workTree = repo.workingTree();
workTree.delete(linesName, lines1.getIdentifier().getID());
geogig.command(AddOp.class).call();
// newRootTreeId
newRootTreeId = geogig.command(WriteTree2.class).setOldRoot(tree(newRootTreeId)).call();
// =
// index.writeTree(newRootTreeId,
// new
// NullProgressListener());
assertNotNull(newRootTreeId);
assertFalse(repo.getRootTreeId().equals(newRootTreeId));
tree = repo.getTree(newRootTreeId);
path = appendChild(pointsName, points1.getIdentifier().getID());
assertTrue(repo.command(FindTreeChild.class).setParent(tree).setChildPath(path).call().isPresent());
path = appendChild(linesName, lines1.getIdentifier().getID());
assertFalse(repo.command(FindTreeChild.class).setParent(tree).setChildPath(path).call().isPresent());
}
use of org.locationtech.geogig.api.plumbing.WriteTree2 in project GeoGig by boundlessgeo.
the class CommitOp method _call.
/**
* Executes the commit operation.
*
* @return the commit just applied, or {@code null} if
* {@code getProgressListener().isCanceled()}
* @see org.locationtech.geogig.api.AbstractGeoGigOp#call()
* @throws NothingToCommitException if there are no staged changes by comparing the index
* staging tree and the repository HEAD tree.
*/
@Override
protected RevCommit _call() throws RuntimeException {
final String committer = resolveCommitter();
final String committerEmail = resolveCommitterEmail();
final String author = resolveAuthor();
final String authorEmail = resolveAuthorEmail();
final Long authorTime = getAuthorTimeStamp();
final Long committerTime = getCommitterTimeStamp();
final Integer authorTimeZoneOffset = getAuthorTimeZoneOffset();
final Integer committerTimeZoneOffset = getCommitterTimeZoneOffset();
getProgressListener().started();
float writeTreeProgress = 99f;
if (all) {
writeTreeProgress = 50f;
AddOp op = command(AddOp.class);
for (String st : pathFilters) {
op.addPattern(st);
}
op.setUpdateOnly(true).setProgressListener(subProgress(49f)).call();
}
if (getProgressListener().isCanceled()) {
return null;
}
final Optional<Ref> currHead = command(RefParse.class).setName(Ref.HEAD).call();
checkState(currHead.isPresent(), "Repository has no HEAD, can't commit");
final Ref headRef = currHead.get();
checkState(//
headRef instanceof SymRef, "HEAD is in a dettached state, cannot commit. Create a branch from it before committing");
final String currentBranch = ((SymRef) headRef).getTarget();
final ObjectId currHeadCommitId = headRef.getObjectId();
Supplier<RevTree> oldRoot = resolveOldRoot();
if (!currHeadCommitId.isNull()) {
if (amend) {
RevCommit headCommit = command(RevObjectParse.class).setObjectId(currHeadCommitId).call(RevCommit.class).get();
parents.addAll(headCommit.getParentIds());
if (message == null || message.isEmpty()) {
message = headCommit.getMessage();
}
RevTree commitTree = command(RevObjectParse.class).setObjectId(headCommit.getTreeId()).call(RevTree.class).get();
oldRoot = Suppliers.ofInstance(commitTree);
} else {
parents.add(0, currHeadCommitId);
}
} else {
Preconditions.checkArgument(!amend, "Cannot amend. There is no previous commit to amend");
}
// additional operations in case we are committing after a conflicted merge
final Optional<Ref> mergeHead = command(RefParse.class).setName(Ref.MERGE_HEAD).call();
if (mergeHead.isPresent()) {
ObjectId mergeCommitId = mergeHead.get().getObjectId();
if (!mergeCommitId.isNull()) {
parents.add(mergeCommitId);
}
if (message == null) {
message = command(ReadMergeCommitMessageOp.class).call();
}
}
ObjectId newTreeId;
{
WriteTree2 writeTree = command(WriteTree2.class);
writeTree.setOldRoot(oldRoot).setProgressListener(subProgress(writeTreeProgress));
if (!pathFilters.isEmpty()) {
writeTree.setPathFilter(pathFilters);
}
newTreeId = writeTree.call();
}
if (getProgressListener().isCanceled()) {
return null;
}
final ObjectId currentRootTreeId = command(ResolveTreeish.class).setTreeish(currHeadCommitId).call().or(RevTree.EMPTY_TREE_ID);
if (currentRootTreeId.equals(newTreeId)) {
if (!allowEmpty) {
throw new NothingToCommitException("Nothing to commit after " + currHeadCommitId);
}
}
final RevCommit commit;
if (this.commit == null) {
CommitBuilder cb = new CommitBuilder();
cb.setAuthor(author);
cb.setAuthorEmail(authorEmail);
cb.setCommitter(committer);
cb.setCommitterEmail(committerEmail);
cb.setMessage(message);
cb.setParentIds(parents);
cb.setTreeId(newTreeId);
cb.setCommitterTimestamp(committerTime);
cb.setAuthorTimestamp(authorTime);
cb.setCommitterTimeZoneOffset(committerTimeZoneOffset);
cb.setAuthorTimeZoneOffset(authorTimeZoneOffset);
commit = cb.build();
} else {
CommitBuilder cb = new CommitBuilder(this.commit);
cb.setParentIds(parents);
cb.setTreeId(newTreeId);
cb.setCommitterTimestamp(committerTime);
cb.setCommitterTimeZoneOffset(committerTimeZoneOffset);
if (message != null) {
cb.setMessage(message);
}
commit = cb.build();
}
if (getProgressListener().isCanceled()) {
return null;
}
final ObjectDatabase objectDb = objectDatabase();
objectDb.put(commit);
// set the HEAD pointing to the new commit
final Optional<Ref> branchHead = command(UpdateRef.class).setName(currentBranch).setNewValue(commit.getId()).call();
checkState(commit.getId().equals(branchHead.get().getObjectId()));
final Optional<Ref> newHead = command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
checkState(currentBranch.equals(((SymRef) newHead.get()).getTarget()));
Optional<ObjectId> treeId = command(ResolveTreeish.class).setTreeish(branchHead.get().getObjectId()).call();
checkState(treeId.isPresent());
checkState(newTreeId.equals(treeId.get()));
getProgressListener().setProgress(100f);
getProgressListener().complete();
// TODO: maybe all this "heads cleaning" should be put in an independent operation
if (mergeHead.isPresent()) {
command(UpdateRef.class).setDelete(true).setName(Ref.MERGE_HEAD).call();
command(UpdateRef.class).setDelete(true).setName(Ref.ORIG_HEAD).call();
}
final Optional<Ref> cherrypickHead = command(RefParse.class).setName(Ref.CHERRY_PICK_HEAD).call();
if (cherrypickHead.isPresent()) {
command(UpdateRef.class).setDelete(true).setName(Ref.CHERRY_PICK_HEAD).call();
command(UpdateRef.class).setDelete(true).setName(Ref.ORIG_HEAD).call();
}
return commit;
}
use of org.locationtech.geogig.api.plumbing.WriteTree2 in project GeoGig by boundlessgeo.
the class RebaseOp method applyCommit.
/**
* Applies the passed command.
*
* @param commitToApply the commit to apply
* @param useCommitChanges if true, applies the command completely, staging its changes before
* committing. If false, it commits the currently staged changes, ignoring the changes in
* the commit and using just its author and message
*/
private void applyCommit(RevCommit commitToApply, boolean useCommitChanges) {
Repository repository = repository();
Platform platform = platform();
if (useCommitChanges) {
ObjectId parentTreeId;
ObjectId parentCommitId = ObjectId.NULL;
if (commitToApply.getParentIds().size() > 0) {
parentCommitId = commitToApply.getParentIds().get(0);
}
parentTreeId = ObjectId.NULL;
if (repository.commitExists(parentCommitId)) {
parentTreeId = repository.getCommit(parentCommitId).getTreeId();
}
// get changes
Iterator<DiffEntry> diff = command(DiffTree.class).setOldTree(parentTreeId).setNewTree(commitToApply.getTreeId()).setReportTrees(true).call();
// see if there are conflicts
MergeScenarioReport report = command(ReportCommitConflictsOp.class).setCommit(commitToApply).call();
if (report.getConflicts().isEmpty()) {
// stage changes
index().stage(getProgressListener(), diff, 0);
// write new tree
ObjectId newTreeId = command(WriteTree2.class).call();
long timestamp = platform.currentTimeMillis();
// Create new commit
CommitBuilder builder = new CommitBuilder(commitToApply);
builder.setParentIds(Arrays.asList(rebaseHead));
builder.setTreeId(newTreeId);
builder.setCommitterTimestamp(timestamp);
builder.setCommitterTimeZoneOffset(platform.timeZoneOffset(timestamp));
RevCommit newCommit = builder.build();
repository.objectDatabase().put(newCommit);
rebaseHead = newCommit.getId();
command(UpdateRef.class).setName(currentBranch).setNewValue(rebaseHead).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(newTreeId);
index().updateStageHead(newTreeId);
} else {
Iterator<DiffEntry> unconflicted = report.getUnconflicted().iterator();
// stage unconflicted changes
index().stage(getProgressListener(), unconflicted, 0);
workingTree().updateWorkHead(index().getTree().getId());
// mark conflicted elements
command(ConflictsWriteOp.class).setConflicts(report.getConflicts()).call();
// created exception message
StringBuilder msg = new StringBuilder();
msg.append("error: could not apply ");
msg.append(commitToApply.getId().toString().substring(0, 7));
msg.append(" " + commitToApply.getMessage() + "\n");
for (Conflict conflict : report.getConflicts()) {
msg.append("CONFLICT: conflict in " + conflict.getPath() + "\n");
}
File branchFile = new File(getRebaseFolder(), "branch");
try {
Files.write(currentBranch, branchFile, Charsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Cannot create current branch info file");
}
throw new RebaseConflictsException(msg.toString());
}
} else {
// write new tree
ObjectId newTreeId = command(WriteTree2.class).call();
long timestamp = platform.currentTimeMillis();
// Create new commit
CommitBuilder builder = new CommitBuilder(commitToApply);
builder.setParentIds(Arrays.asList(rebaseHead));
builder.setTreeId(newTreeId);
builder.setCommitterTimestamp(timestamp);
builder.setCommitterTimeZoneOffset(platform.timeZoneOffset(timestamp));
RevCommit newCommit = builder.build();
repository.objectDatabase().put(newCommit);
rebaseHead = newCommit.getId();
command(UpdateRef.class).setName(currentBranch).setNewValue(rebaseHead).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(newTreeId);
index().updateStageHead(newTreeId);
}
}
use of org.locationtech.geogig.api.plumbing.WriteTree2 in project GeoGig by boundlessgeo.
the class RevertOp method createCommit.
private void createCommit(RevCommit commit) {
// write new tree
ObjectId newTreeId = command(WriteTree2.class).call();
long timestamp = platform().currentTimeMillis();
String committerName = resolveCommitter();
String committerEmail = resolveCommitterEmail();
// Create new commit
CommitBuilder builder = new CommitBuilder();
builder.setParentIds(Arrays.asList(revertHead));
builder.setTreeId(newTreeId);
builder.setCommitterTimestamp(timestamp);
builder.setMessage("Revert '" + commit.getMessage() + "'\nThis reverts " + commit.getId().toString());
builder.setCommitter(committerName);
builder.setCommitterEmail(committerEmail);
builder.setAuthor(committerName);
builder.setAuthorEmail(committerEmail);
RevCommit newCommit = builder.build();
objectDatabase().put(newCommit);
revertHead = newCommit.getId();
command(UpdateRef.class).setName(currentBranch).setNewValue(revertHead).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(newTreeId);
index().updateStageHead(newTreeId);
}
use of org.locationtech.geogig.api.plumbing.WriteTree2 in project GeoGig by boundlessgeo.
the class CherryPickOp method _call.
/**
* Executes the cherry pick operation.
*
* @return RevCommit the new commit with the changes from the cherry-picked commit
*/
@Override
protected RevCommit _call() {
final Repository repository = repository();
final Optional<Ref> currHead = command(RefParse.class).setName(Ref.HEAD).call();
Preconditions.checkState(currHead.isPresent(), "Repository has no HEAD, can't cherry pick.");
Preconditions.checkState(currHead.get() instanceof SymRef, "Can't cherry pick from detached HEAD");
final SymRef headRef = (SymRef) currHead.get();
Preconditions.checkState(index().isClean() && workingTree().isClean(), "You must have a clean working tree and index to perform a cherry pick.");
getProgressListener().started();
Preconditions.checkArgument(repository.commitExists(commit), "Commit could not be resolved: %s.", commit);
RevCommit commitToApply = repository.getCommit(commit);
ObjectId headId = headRef.getObjectId();
ObjectId parentCommitId = ObjectId.NULL;
if (commitToApply.getParentIds().size() > 0) {
parentCommitId = commitToApply.getParentIds().get(0);
}
ObjectId parentTreeId = ObjectId.NULL;
if (repository.commitExists(parentCommitId)) {
parentTreeId = repository.getCommit(parentCommitId).getTreeId();
}
// get changes
Iterator<DiffEntry> diff = command(DiffTree.class).setOldTree(parentTreeId).setNewTree(commitToApply.getTreeId()).setReportTrees(true).call();
// see if there are conflicts
MergeScenarioReport report = command(ReportCommitConflictsOp.class).setCommit(commitToApply).call();
if (report.getConflicts().isEmpty()) {
// stage changes
index().stage(getProgressListener(), diff, 0);
// write new tree
ObjectId newTreeId = command(WriteTree2.class).call();
RevCommit newCommit = command(CommitOp.class).setCommit(commitToApply).call();
repository.workingTree().updateWorkHead(newTreeId);
repository.index().updateStageHead(newTreeId);
getProgressListener().complete();
return newCommit;
} else {
Iterator<DiffEntry> unconflicted = report.getUnconflicted().iterator();
// stage changes
index().stage(getProgressListener(), unconflicted, 0);
workingTree().updateWorkHead(index().getTree().getId());
command(UpdateRef.class).setName(Ref.CHERRY_PICK_HEAD).setNewValue(commit).call();
command(UpdateRef.class).setName(Ref.ORIG_HEAD).setNewValue(headId).call();
command(ConflictsWriteOp.class).setConflicts(report.getConflicts()).call();
StringBuilder msg = new StringBuilder();
msg.append("error: could not apply ");
msg.append(commitToApply.getId().toString().substring(0, 7));
msg.append(" " + commitToApply.getMessage());
for (Conflict conflict : report.getConflicts()) {
msg.append("\t" + conflict.getPath() + "\n");
}
StringBuilder sb = new StringBuilder();
for (Conflict conflict : report.getConflicts()) {
sb.append("CONFLICT: conflict in " + conflict.getPath() + "\n");
}
sb.append("Fix conflicts and then commit the result using 'geogig commit -c " + commitToApply.getId().toString().substring(0, 7) + "\n");
throw new IllegalStateException(sb.toString());
}
}
Aggregations