View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.scm.provider.git.jgit.command.info;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.LinkedList;
24  import java.util.List;
25  
26  import org.apache.commons.lang3.StringUtils;
27  import org.apache.maven.scm.CommandParameters;
28  import org.apache.maven.scm.ScmException;
29  import org.apache.maven.scm.ScmFileSet;
30  import org.apache.maven.scm.ScmResult;
31  import org.apache.maven.scm.command.AbstractCommand;
32  import org.apache.maven.scm.command.info.InfoItem;
33  import org.apache.maven.scm.command.info.InfoScmResult;
34  import org.apache.maven.scm.provider.ScmProviderRepository;
35  import org.apache.maven.scm.provider.git.command.GitCommand;
36  import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
37  import org.eclipse.jgit.api.Git;
38  import org.eclipse.jgit.lib.Constants;
39  import org.eclipse.jgit.lib.ObjectId;
40  import org.eclipse.jgit.lib.PersonIdent;
41  import org.eclipse.jgit.lib.Repository;
42  import org.eclipse.jgit.revwalk.RevCommit;
43  import org.eclipse.jgit.revwalk.RevSort;
44  import org.eclipse.jgit.revwalk.RevWalk;
45  import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
46  import org.eclipse.jgit.treewalk.filter.PathFilter;
47  import org.eclipse.jgit.treewalk.filter.TreeFilter;
48  
49  /**
50   * @since 1.9.5
51   */
52  public class JGitInfoCommand extends AbstractCommand implements GitCommand {
53      @Override
54      protected ScmResult executeCommand(
55              ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
56          File basedir = fileSet.getBasedir();
57          Git git = null;
58          try {
59              git = JGitUtils.openRepo(basedir);
60              ObjectId objectId = git.getRepository().resolve(Constants.HEAD);
61              if (objectId == null) {
62                  throw new ScmException("Cannot resolve HEAD in git repository at " + basedir);
63              }
64  
65              List<InfoItem> infoItems = new LinkedList<>();
66              if (fileSet.getFileList().isEmpty()) {
67                  RevCommit headCommit = git.getRepository().parseCommit(objectId);
68                  infoItems.add(getInfoItem(headCommit, fileSet.getBasedir()));
69              } else {
70                  // iterate over all files
71                  for (File file : JGitUtils.getWorkingCopyRelativePaths(
72                          git.getRepository().getWorkTree(), fileSet)) {
73                      infoItems.add(getInfoItem(git.getRepository(), objectId, file));
74                  }
75              }
76              return new InfoScmResult(infoItems, new ScmResult("JGit.resolve(HEAD)", "", objectId.toString(), true));
77          } catch (Exception e) {
78              throw new ScmException("JGit resolve failure!", e);
79          } finally {
80              JGitUtils.closeRepo(git);
81          }
82      }
83  
84      protected InfoItem getInfoItem(Repository repository, ObjectId headObjectId, File file) throws IOException {
85          RevCommit commit = getMostRecentCommitForPath(repository, headObjectId, JGitUtils.toNormalizedFilePath(file));
86          return getInfoItem(commit, file);
87      }
88  
89      protected InfoItem getInfoItem(RevCommit fileCommit, File file) {
90          InfoItem infoItem = new InfoItem();
91          infoItem.setPath(file.getPath());
92          infoItem.setRevision(StringUtils.trim(fileCommit.name()));
93          infoItem.setURL(file.toPath().toUri().toASCIIString());
94          PersonIdent authorIdent = fileCommit.getAuthorIdent();
95          infoItem.setLastChangedDateTime(authorIdent
96                  .getWhen()
97                  .toInstant()
98                  .atZone(authorIdent.getTimeZone().toZoneId()));
99          infoItem.setLastChangedAuthor(authorIdent.getName() + " <" + authorIdent.getEmailAddress() + ">");
100         return infoItem;
101     }
102 
103     private RevCommit getMostRecentCommitForPath(Repository repository, ObjectId headObjectId, String path)
104             throws IOException {
105         RevCommit latestCommit = null;
106         try (RevWalk revWalk = new RevWalk(repository)) {
107             RevCommit headCommit = revWalk.parseCommit(headObjectId);
108             revWalk.markStart(headCommit);
109             revWalk.sort(RevSort.COMMIT_TIME_DESC);
110             revWalk.setTreeFilter(AndTreeFilter.create(PathFilter.create(path), TreeFilter.ANY_DIFF));
111             latestCommit = revWalk.next();
112         }
113         return latestCommit;
114     }
115 }