Search in sources :

Example 16 with Repository

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;
}
Also used : RepositoryListener(org.locationtech.geogig.repository.Repository.RepositoryListener) Repository(org.locationtech.geogig.repository.Repository)

Example 17 with Repository

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;
}
Also used : Repository(org.locationtech.geogig.repository.Repository) Platform(org.locationtech.geogig.api.Platform) File(java.io.File)

Example 18 with 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;
}
Also used : ConflictsReadOp(org.locationtech.geogig.api.plumbing.merge.ConflictsReadOp) ObjectId(org.locationtech.geogig.api.ObjectId) ArrayList(java.util.ArrayList) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) CommitBuilder(org.locationtech.geogig.api.CommitBuilder) IOException(java.io.IOException) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) Ref(org.locationtech.geogig.api.Ref) SymRef(org.locationtech.geogig.api.SymRef) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) SymRef(org.locationtech.geogig.api.SymRef) Repository(org.locationtech.geogig.repository.Repository) Conflict(org.locationtech.geogig.api.plumbing.merge.Conflict) CanRunDuringConflict(org.locationtech.geogig.di.CanRunDuringConflict) File(java.io.File) RevCommit(org.locationtech.geogig.api.RevCommit)

Example 19 with Repository

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);
    }
}
Also used : Platform(org.locationtech.geogig.api.Platform) ObjectId(org.locationtech.geogig.api.ObjectId) CommitBuilder(org.locationtech.geogig.api.CommitBuilder) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) IOException(java.io.IOException) MergeScenarioReport(org.locationtech.geogig.api.plumbing.merge.MergeScenarioReport) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) Repository(org.locationtech.geogig.repository.Repository) Conflict(org.locationtech.geogig.api.plumbing.merge.Conflict) CanRunDuringConflict(org.locationtech.geogig.di.CanRunDuringConflict) File(java.io.File) WriteTree2(org.locationtech.geogig.api.plumbing.WriteTree2) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry) RevCommit(org.locationtech.geogig.api.RevCommit)

Example 20 with Repository

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;
}
Also used : Platform(org.locationtech.geogig.api.Platform) GraphDatabase(org.locationtech.geogig.storage.GraphDatabase) CommitBuilder(org.locationtech.geogig.api.CommitBuilder) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) SymRef(org.locationtech.geogig.api.SymRef) RevCommit(org.locationtech.geogig.api.RevCommit) ObjectId(org.locationtech.geogig.api.ObjectId) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) Repository(org.locationtech.geogig.repository.Repository) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) ForEachRef(org.locationtech.geogig.api.plumbing.ForEachRef) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) Ref(org.locationtech.geogig.api.Ref) SymRef(org.locationtech.geogig.api.SymRef) FindCommonAncestor(org.locationtech.geogig.api.plumbing.FindCommonAncestor)

Aggregations

Repository (org.locationtech.geogig.repository.Repository)30 ObjectId (org.locationtech.geogig.api.ObjectId)13 RevCommit (org.locationtech.geogig.api.RevCommit)11 File (java.io.File)10 IOException (java.io.IOException)9 Ref (org.locationtech.geogig.api.Ref)9 UpdateRef (org.locationtech.geogig.api.plumbing.UpdateRef)9 DiffEntry (org.locationtech.geogig.api.plumbing.diff.DiffEntry)8 GeoGIG (org.locationtech.geogig.api.GeoGIG)7 UpdateSymRef (org.locationtech.geogig.api.plumbing.UpdateSymRef)7 SymRef (org.locationtech.geogig.api.SymRef)6 ArrayList (java.util.ArrayList)5 NodeRef (org.locationtech.geogig.api.NodeRef)5 Conflict (org.locationtech.geogig.api.plumbing.merge.Conflict)5 CommitBuilder (org.locationtech.geogig.api.CommitBuilder)4 Platform (org.locationtech.geogig.api.Platform)4 RevObject (org.locationtech.geogig.api.RevObject)4 CanRunDuringConflict (org.locationtech.geogig.di.CanRunDuringConflict)4 LinkedList (java.util.LinkedList)3 RevTree (org.locationtech.geogig.api.RevTree)3