@Override public Document execute( Repository repository, Git git, CallSpecification spec, DocumentWriter writer, Values values) throws GitAPIException, IOException { if (spec.parameterCount() == 0) { // This is the top-level "/branches" node writer.setPrimaryType(GitLexicon.TREES); // Generate the child references to the branches and tags. Branches are likely used more // often, so list them first... addBranchesAsChildren(git, spec, writer); addTagsAsChildren(git, spec, writer); addCommitsAsChildren(git, spec, writer, pageSize); } else if (spec.parameterCount() == 1) { // This is a particular branch/tag/commit node ... String branchOrTagOrObjectId = spec.parameter(0); ObjectId objId = resolveBranchOrTagOrCommitId(repository, branchOrTagOrObjectId); RevWalk walker = new RevWalk(repository); walker.setRetainBody(true); // we need to parse the commit for the top-level try { RevCommit commit = walker.parseCommit(objId); // Add the properties for this node ... String committer = commit.getCommitterIdent().getName(); String author = commit.getAuthorIdent().getName(); DateTime committed = values.dateFrom(commit.getCommitTime()); writer.setPrimaryType(GitLexicon.FOLDER); writer.addProperty(JcrLexicon.CREATED, committed); writer.addProperty(JcrLexicon.CREATED_BY, committer); writer.addProperty(GitLexicon.OBJECT_ID, objId.name()); writer.addProperty(GitLexicon.AUTHOR, author); writer.addProperty(GitLexicon.COMMITTER, committer); writer.addProperty(GitLexicon.COMMITTED, committed); writer.addProperty(GitLexicon.TITLE, commit.getShortMessage()); writer.addProperty( GitLexicon.HISTORY, GitHistory.referenceToHistory(objId, branchOrTagOrObjectId, values)); writer.addProperty(GitLexicon.DETAIL, GitCommitDetails.referenceToCommit(objId, values)); // Add the top-level children of the directory ... addInformationForPath(repository, git, writer, commit, "", spec, values); } finally { walker.dispose(); } } else { // This is a folder or file within the directory structure ... String branchOrTagOrObjectId = spec.parameter(0); String path = spec.parametersAsPath(1); ObjectId objId = resolveBranchOrTagOrCommitId(repository, branchOrTagOrObjectId); RevWalk walker = new RevWalk(repository); walker.setRetainBody(false); // we don't need top-level commit information try { // Get the commit information ... RevCommit commit = walker.parseCommit(objId); // Add the top-level children of the directory ... addInformationForPath(repository, git, writer, commit, path, spec, values); } finally { walker.dispose(); } } return writer.document(); }
protected void addInformationForPath( Repository repository, Git git, DocumentWriter writer, RevCommit commit, String path, CallSpecification spec, Values values) throws GitAPIException, IOException { // Make sure the path is in the canonical form we need ... if (path.startsWith("/")) { if (path.length() == 1) path = ""; else path = path.substring(1); } // Now see if we're actually referring to the "jcr:content" node ... boolean isContentNode = false; if (path.endsWith(JCR_CONTENT_SUFFIX)) { isContentNode = true; path = path.substring(0, path.length() - JCR_CONTENT_SUFFIX.length()); } // Create the TreeWalk that we'll use to navigate the files/directories ... final TreeWalk tw = new TreeWalk(repository); tw.addTree(commit.getTree()); if ("".equals(path)) { // This is the top-level directory, so we don't need to pre-walk to find anything ... tw.setRecursive(false); while (tw.next()) { String childName = tw.getNameString(); String childId = spec.childId(childName); writer.addChild(childId, childName); } } else { // We need to first find our path *before* we can walk the children ... PathFilter filter = PathFilter.create(path); tw.setFilter(filter); while (tw.next()) { if (filter.isDone(tw)) { break; } else if (tw.isSubtree()) { tw.enterSubtree(); } } // Now that the TreeWalk is the in right location given by the 'path', we can get the if (tw.isSubtree()) { // The object at the 'path' is a directory, so go into it ... tw.enterSubtree(); // Find the commit in which this folder was last modified ... // This may not be terribly efficient, but it seems to work faster on subsequent runs ... RevCommit folderCommit = git.log().addPath(path).call().iterator().next(); // Add folder-related properties ... String committer = folderCommit.getCommitterIdent().getName(); String author = folderCommit.getAuthorIdent().getName(); DateTime committed = values.dateFrom(folderCommit.getCommitTime()); writer.setPrimaryType(GitLexicon.FOLDER); writer.addProperty(JcrLexicon.CREATED, committed); writer.addProperty(JcrLexicon.CREATED_BY, committer); writer.addProperty(GitLexicon.OBJECT_ID, folderCommit.getId().name()); writer.addProperty(GitLexicon.AUTHOR, author); writer.addProperty(GitLexicon.COMMITTER, committer); writer.addProperty(GitLexicon.COMMITTED, committed); writer.addProperty(GitLexicon.TITLE, folderCommit.getShortMessage()); // And now walk the contents of the directory ... while (tw.next()) { String childName = tw.getNameString(); String childId = spec.childId(childName); writer.addChild(childId, childName); } } else { // The path specifies a file (or a content node) ... // Find the commit in which this folder was last modified ... // This may not be terribly efficient, but it seems to work faster on subsequent runs ... RevCommit fileCommit = git.log().addPath(path).call().iterator().next(); // Add file-related properties ... String committer = fileCommit.getCommitterIdent().getName(); String author = fileCommit.getAuthorIdent().getName(); DateTime committed = values.dateFrom(fileCommit.getCommitTime()); if (isContentNode) { writer.setPrimaryType(GitLexicon.RESOURCE); writer.addProperty(JcrLexicon.LAST_MODIFIED, committed); writer.addProperty(JcrLexicon.LAST_MODIFIED_BY, committer); writer.addProperty(GitLexicon.OBJECT_ID, fileCommit.getId().name()); writer.addProperty(GitLexicon.AUTHOR, author); writer.addProperty(GitLexicon.COMMITTER, committer); writer.addProperty(GitLexicon.COMMITTED, committed); writer.addProperty(GitLexicon.TITLE, fileCommit.getShortMessage()); // Create the BinaryValue ... ObjectId fileObjectId = tw.getObjectId(0); ObjectLoader fileLoader = repository.open(fileObjectId); BinaryKey key = new BinaryKey(fileObjectId.getName()); BinaryValue value = values.binaryFor(key, fileLoader.getSize()); if (value == null) { // It wasn't found in the binary store ... if (fileLoader.isLarge()) { // Too large to hold in memory, so use the binary store (which reads the file // immediately) ... value = values.binaryFrom(fileLoader.openStream()); } else { // This is small enough to fit into a byte[], but it still may be pretty big ... value = new GitBinaryValue( fileObjectId, fileLoader, connector.getSourceName(), name, connector.getMimeTypeDetector()); } } writer.addProperty(JcrLexicon.DATA, value); if (connector.includeMimeType()) { try { String filename = spec.parameter(spec.parameterCount() - 1); // the last is 'jcr:content' String mimeType = value.getMimeType(filename); if (mimeType != null) writer.addProperty(JcrLexicon.MIMETYPE, mimeType); } catch (RepositoryException e) { // do nothing } catch (IOException e) { // do nothing } } } else { writer.setPrimaryType(GitLexicon.FILE); writer.addProperty(JcrLexicon.CREATED, committed); writer.addProperty(JcrLexicon.CREATED_BY, committer); writer.addProperty(GitLexicon.OBJECT_ID, fileCommit.getId().name()); writer.addProperty(GitLexicon.AUTHOR, author); writer.addProperty(GitLexicon.COMMITTER, committer); writer.addProperty(GitLexicon.COMMITTED, committed); writer.addProperty(GitLexicon.TITLE, fileCommit.getShortMessage()); // Add the "jcr:content" child node ... String childId = spec.childId(JCR_CONTENT); writer.addChild(childId, JCR_CONTENT); } } } }