001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.connector.git;
017
018import java.io.IOException;
019import org.eclipse.jgit.api.Git;
020import org.eclipse.jgit.api.errors.GitAPIException;
021import org.eclipse.jgit.lib.ObjectId;
022import org.eclipse.jgit.lib.Repository;
023import org.eclipse.jgit.revwalk.RevCommit;
024import org.eclipse.jgit.revwalk.RevWalk;
025import org.modeshape.schematic.document.Document;
026import org.modeshape.jcr.spi.federation.DocumentWriter;
027import org.modeshape.jcr.spi.federation.PageKey;
028import org.modeshape.jcr.spi.federation.PageWriter;
029
030/**
031 * A {@link GitFunction} that returns the history information about the (latest) commits in a particular branch or tag. The
032 * structure of this area of the repository is as follows:
033 * 
034 * <pre>
035 *   /commits/{branchOrTagNameOrObjectId}/{objectId}
036 * </pre>
037 */
038public class GitHistory extends GitFunction implements PageableGitFunction {
039
040    protected static Object referenceToHistory( ObjectId id,
041                                                String branchOrTagName,
042                                                Values values ) {
043        return values.referenceTo(ID + DELIMITER + branchOrTagName + DELIMITER + id.getName());
044    }
045
046    protected static final String NAME = "commits";
047    protected static final String ID = "/commits";
048
049    protected static int DEFAULT_PAGE_SIZE = 15;
050
051    private int pageSize = DEFAULT_PAGE_SIZE;
052
053    public GitHistory( GitConnector connector ) {
054        super(NAME, connector);
055    }
056
057    @Override
058    public boolean isPaged() {
059        return true;
060    }
061
062    @Override
063    public Document execute( Repository repository,
064                             Git git,
065                             CallSpecification spec,
066                             DocumentWriter writer,
067                             Values values ) throws GitAPIException, IOException {
068        if (spec.parameterCount() == 0) {
069            // This is the top-level "/commits" node
070            writer.setPrimaryType(GitLexicon.COMMITS);
071
072            // Generate the child references to the branches, tags, and commits in the history ...
073            addBranchesAsChildren(git, spec, writer);
074            addTagsAsChildren(git, spec, writer);
075            addCommitsAsChildren(git, spec, writer, pageSize);
076
077        } else if (spec.parameterCount() == 1) {
078            // This is the top-level "/commits/{branchOrTagNameOrObjectId}" node
079            writer.setPrimaryType(GitLexicon.OBJECT);
080            addCommitsAsChildren(git, spec, writer, pageSize);
081        } else if (spec.parameterCount() == 2) {
082            // This is a specific commit in the history, via "/commits/{branchOrTagNameOrObjectId}/{objectId}"
083            writer.setPrimaryType(GitLexicon.COMMIT);
084
085            // so we need to show the commit information ...
086            RevWalk walker = new RevWalk(repository);
087            try {
088                String commitId = spec.parameter(1);
089                ObjectId objId = repository.resolve(commitId);
090                RevCommit commit = walker.parseCommit(objId);
091                writer.addProperty(GitLexicon.OBJECT_ID, objId.name());
092                writer.addProperty(GitLexicon.AUTHOR, authorName(commit));
093                writer.addProperty(GitLexicon.COMMITTER, commiterName(commit));
094                writer.addProperty(GitLexicon.COMMITTED, values.dateFrom(commit.getCommitTime()));
095                writer.addProperty(GitLexicon.TITLE, commit.getShortMessage());
096                writer.addProperty(GitLexicon.TREE, GitTree.referenceToTree(objId, objId.name(), values));
097                writer.addProperty(GitLexicon.DETAIL, GitCommitDetails.referenceToCommit(objId, values));
098                // And there are no children
099            } finally {
100                walker.dispose();
101            }
102        } else {
103            return null;
104        }
105
106        return writer.document();
107    }
108
109    @Override
110    public Document execute( Repository repository,
111                             Git git,
112                             CallSpecification spec,
113                             PageWriter writer,
114                             Values values,
115                             PageKey pageKey ) throws GitAPIException, IOException {
116        // List the next page of commits ...
117        addCommitsAsPageOfChildren(git, repository, spec, writer, pageKey);
118        return writer.document();
119    }
120}