use of org.locationtech.geogig.repository.Repository in project GeoGig by boundlessgeo.
the class RepositoryDecorator method decorate.
@Override
public <I> I decorate(I subject) {
if (listener == null) {
listener = new RepositoryListener() {
@Override
public void opened(Repository repo) {
service.startAsync().awaitRunning();
}
@Override
public void closed() {
service.stopAsync();
}
};
((Repository) subject).addListener(listener);
}
return subject;
}
use of org.locationtech.geogig.repository.Repository in project GeoGig by boundlessgeo.
the class InitOp method _call.
/**
* Executes the Init operation.
*
* @return the initialized repository
* @throws IllegalStateException if a repository cannot be created on the current directory or
* re-initialized in the current dir or one if its parents as determined by
* {@link ResolveGeogigDir}
*/
@Override
protected Repository _call() {
final Platform platform = platform();
final File workingDirectory = platform.pwd();
checkState(workingDirectory != null, "working directory is null");
final File targetDir = this.targetDir == null ? workingDirectory : this.targetDir;
if (!targetDir.exists() && !targetDir.mkdirs()) {
throw new IllegalArgumentException("Can't create directory " + targetDir.getAbsolutePath());
}
Repository repository;
try {
platform.setWorkingDir(targetDir);
repository = callInternal();
} finally {
// restore current directory
platform.setWorkingDir(workingDirectory);
}
return repository;
}
use of org.locationtech.geogig.repository.Repository in project GeoGig by boundlessgeo.
the class RebaseOp method _call.
/**
* Executes the rebase operation.
*
* @return always {@code true}
*/
@Override
protected Boolean _call() {
final Optional<Ref> currHead = command(RefParse.class).setName(Ref.HEAD).call();
Preconditions.checkState(currHead.isPresent(), "Repository has no HEAD, can't rebase.");
if (!(continueRebase || skip || abort)) {
Preconditions.checkState(currHead.get() instanceof SymRef, "Can't rebase from detached HEAD %s", currHead.get());
Preconditions.checkState(upstream != null, "No upstream target has been specified.");
Preconditions.checkState(!ObjectId.NULL.equals(upstream.get()), "Upstream did not resolve to a commit.");
}
// Rebase can only be run in a conflicted situation if the skip or abort option is used
List<Conflict> conflicts = command(ConflictsReadOp.class).call();
Preconditions.checkState(conflicts.isEmpty() || skip || abort, "Cannot run operation while merge conflicts exist.");
Optional<Ref> ref = command(RefParse.class).setName(Ref.ORIG_HEAD).call();
File branchFile = new File(getRebaseFolder(), "branch");
RevCommit squashCommit = readSquashCommit();
if (abort) {
Preconditions.checkState(ref.isPresent() && branchFile.exists(), "Cannot abort. You are not in the middle of a rebase process.");
command(ResetOp.class).setMode(ResetMode.HARD).setCommit(Suppliers.ofInstance(ref.get().getObjectId())).call();
command(UpdateRef.class).setDelete(true).setName(Ref.ORIG_HEAD).call();
branchFile.delete();
return true;
} else if (continueRebase) {
Preconditions.checkState(ref.isPresent() && branchFile.exists(), "Cannot continue. You are not in the middle of a rebase process.");
try {
currentBranch = Files.readFirstLine(branchFile, Charsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Cannot read current branch info file");
}
rebaseHead = currHead.get().getObjectId();
if (squashCommit == null) {
// Commit the manually-merged changes with the info of the commit that caused the
// conflict
applyNextCommit(false);
// Commit files should already be prepared, so we do nothing else
} else {
applyCommit(squashCommit, false);
}
} else if (skip) {
Preconditions.checkState(ref.isPresent() && branchFile.exists(), "Cannot skip. You are not in the middle of a rebase process.");
try {
currentBranch = Files.readFirstLine(branchFile, Charsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Cannot read current branch info file");
}
rebaseHead = currHead.get().getObjectId();
command(ResetOp.class).setCommit(Suppliers.ofInstance(rebaseHead)).setMode(ResetMode.HARD).call();
if (squashCommit == null) {
skipCurrentCommit();
applyNextCommit(true);
} else {
return true;
}
} else {
Preconditions.checkState(!ref.isPresent(), "You are currently in the middle of a merge or rebase project <ORIG_HEAD is present>.");
getProgressListener().started();
command(UpdateRef.class).setName(Ref.ORIG_HEAD).setNewValue(currHead.get().getObjectId()).call();
// Here we prepare the files with the info about the commits to apply or, if that's not
// needed, do a fast-forward
final SymRef headRef = (SymRef) currHead.get();
currentBranch = headRef.getTarget();
if (ObjectId.NULL.equals(headRef.getObjectId())) {
// Fast-forward
command(UpdateRef.class).setName(currentBranch).setNewValue(upstream.get()).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(upstream.get());
index().updateStageHead(upstream.get());
getProgressListener().complete();
return true;
}
Repository repository = repository();
final RevCommit headCommit = repository.getCommit(headRef.getObjectId());
final RevCommit targetCommit = repository.getCommit(upstream.get());
command(UpdateRef.class).setName(Ref.ORIG_HEAD).setNewValue(headCommit.getId());
Optional<ObjectId> ancestorCommit = command(FindCommonAncestor.class).setLeft(headCommit).setRight(targetCommit).setProgressListener(subProgress(10.f)).call();
Preconditions.checkState(ancestorCommit.isPresent(), "No ancestor commit could be found.");
if (ancestorCommit.get().equals(headCommit.getId())) {
// Fast-forward
command(UpdateRef.class).setName(currentBranch).setNewValue(upstream.get()).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(upstream.get());
index().updateStageHead(upstream.get());
getProgressListener().complete();
return true;
}
// Get all commits between the head commit and the ancestor.
Iterator<RevCommit> commitIterator = command(LogOp.class).call();
List<RevCommit> commitsToRebase = new ArrayList<RevCommit>();
RevCommit commit = commitIterator.next();
while (!commit.getId().equals(ancestorCommit.get())) {
commitsToRebase.add(commit);
commit = commitIterator.next();
}
// rewind the HEAD
if (onto == null) {
onto = Suppliers.ofInstance(upstream.get());
}
rebaseHead = onto.get();
command(ResetOp.class).setCommit(Suppliers.ofInstance(rebaseHead)).setMode(ResetMode.HARD).call();
if (squashMessage != null) {
CommitBuilder builder = new CommitBuilder(commitsToRebase.get(0));
builder.setParentIds(Arrays.asList(ancestorCommit.get()));
builder.setMessage(squashMessage);
squashCommit = builder.build();
// save the commit, since it does not exist in the database, and might be needed if
// there is a conflict
CharSequence commitString = command(CatObject.class).setObject(Suppliers.ofInstance(squashCommit)).call();
File squashFile = new File(getRebaseFolder(), "squash");
try {
Files.write(commitString, squashFile, Charsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Cannot create squash commit info file");
}
applyCommit(squashCommit, true);
return true;
} else {
createRebaseCommitsInfoFiles(commitsToRebase);
}
// ProgressListener subProgress = subProgress(90.f);
}
if (squashCommit == null) {
boolean ret;
do {
ret = applyNextCommit(true);
} while (ret);
}
// clean up
File squashFile = new File(getRebaseFolder(), "squash");
if (squashFile.exists()) {
squashFile.delete();
}
command(UpdateRef.class).setDelete(true).setName(Ref.ORIG_HEAD).call();
branchFile.delete();
// subProgress.complete();
getProgressListener().complete();
return true;
}
use of org.locationtech.geogig.repository.Repository 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.repository.Repository in project GeoGig by boundlessgeo.
the class SquashOp method _call.
/**
* Executes the squash operation.
*
* @return the new head after modifying the history squashing commits
* @see org.locationtech.geogig.api.AbstractGeoGigOp#call()
*/
@Override
protected ObjectId _call() {
Preconditions.checkNotNull(since);
Preconditions.checkNotNull(until);
GraphDatabase graphDb = graphDatabase();
Repository repository = repository();
Platform platform = platform();
final Optional<Ref> currHead = command(RefParse.class).setName(Ref.HEAD).call();
Preconditions.checkState(currHead.isPresent(), "Repository has no HEAD, can't squash.");
Preconditions.checkState(currHead.get() instanceof SymRef, "Can't squash from detached HEAD");
final SymRef headRef = (SymRef) currHead.get();
final String currentBranch = headRef.getTarget();
Preconditions.checkState(index().isClean() && workingTree().isClean(), "You must have a clean working tree and index to perform a squash.");
Optional<ObjectId> ancestor = command(FindCommonAncestor.class).setLeft(since).setRight(until).call();
Preconditions.checkArgument(ancestor.isPresent(), "'since' and 'until' command do not have a common ancestor");
Preconditions.checkArgument(ancestor.get().equals(since.getId()), "Commits provided in wrong order");
Preconditions.checkArgument(!since.getParentIds().isEmpty(), "'since' commit has no parents");
// we get a a list of commits to apply on top of the squashed commits
List<RevCommit> commits = getCommitsAfterUntil();
ImmutableSet<Ref> refs = command(ForEachRef.class).setPrefixFilter(Ref.HEADS_PREFIX).call();
// we create a list of all parents of those squashed commits, in case they are
// merge commits. The resulting commit will have all these parents
//
// While iterating the set of commits to squash, we check that there are no branch starting
// points among them. Any commit with more than one child causes an exception to be thrown,
// since the squash operation does not support squashing those commits
Iterator<RevCommit> toSquash = command(LogOp.class).setSince(since.getParentIds().get(0)).setUntil(until.getId()).setFirstParentOnly(true).call();
List<ObjectId> firstParents = Lists.newArrayList();
List<ObjectId> secondaryParents = Lists.newArrayList();
final List<ObjectId> squashedIds = Lists.newArrayList();
RevCommit commitToSquash = until;
while (toSquash.hasNext()) {
commitToSquash = toSquash.next();
squashedIds.add(commitToSquash.getId());
Preconditions.checkArgument(graphDb.getChildren(commitToSquash.getId()).size() < 2, "The commits to squash include a branch starting point. Squashing that type of commit is not supported.");
for (Ref ref : refs) {
// In case a branch has been created but no commit has been made on it and the
// starting commit has just one child
Preconditions.checkArgument(!ref.getObjectId().equals(commitToSquash.getId()) || ref.getObjectId().equals(currHead.get().getObjectId()) || commitToSquash.getParentIds().size() > 1, "The commits to squash include a branch starting point. Squashing that type of commit is not supported.");
}
ImmutableList<ObjectId> parentIds = commitToSquash.getParentIds();
for (int i = 1; i < parentIds.size(); i++) {
secondaryParents.add(parentIds.get(i));
}
firstParents.add(parentIds.get(0));
}
Preconditions.checkArgument(since.equals(commitToSquash), "Cannot reach 'since' from 'until' commit through first parentage");
// We do the same check in the children commits
for (RevCommit commit : commits) {
Preconditions.checkArgument(graphDb.getChildren(commit.getId()).size() < 2, "The commits after the ones to squash include a branch starting point. This scenario is not supported.");
for (Ref ref : refs) {
// In case a branch has been created but no commit has been made on it
Preconditions.checkArgument(!ref.getObjectId().equals(commit.getId()) || ref.getObjectId().equals(currHead.get().getObjectId()) || commit.getParentIds().size() > 1, "The commits after the ones to squash include a branch starting point. This scenario is not supported.");
}
}
ObjectId newHead;
// rewind the head
newHead = since.getParentIds().get(0);
command(ResetOp.class).setCommit(Suppliers.ofInstance(newHead)).setMode(ResetMode.HARD).call();
// add the current HEAD as first parent of the resulting commit
// parents.add(0, newHead);
// Create new commit
List<ObjectId> parents = Lists.newArrayList();
parents.addAll(firstParents);
parents.addAll(secondaryParents);
ObjectId endTree = until.getTreeId();
CommitBuilder builder = new CommitBuilder(until);
Collection<ObjectId> filteredParents = Collections2.filter(parents, new Predicate<ObjectId>() {
@Override
public boolean apply(@Nullable ObjectId id) {
return !squashedIds.contains(id);
}
});
builder.setParentIds(Lists.newArrayList(filteredParents));
builder.setTreeId(endTree);
if (message == null) {
message = since.getMessage();
}
long timestamp = platform.currentTimeMillis();
builder.setMessage(message);
builder.setCommitter(resolveCommitter());
builder.setCommitterEmail(resolveCommitterEmail());
builder.setCommitterTimestamp(timestamp);
builder.setCommitterTimeZoneOffset(platform.timeZoneOffset(timestamp));
builder.setAuthorTimestamp(until.getAuthor().getTimestamp());
RevCommit newCommit = builder.build();
repository.objectDatabase().put(newCommit);
newHead = newCommit.getId();
ObjectId newTreeId = newCommit.getTreeId();
command(UpdateRef.class).setName(currentBranch).setNewValue(newHead).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(newTreeId);
index().updateStageHead(newTreeId);
// now put the other commits after the squashed one
newHead = addCommits(commits, currentBranch, newHead);
return newHead;
}
Aggregations