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.diff;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.IOException;
23  import java.io.OutputStream;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.maven.scm.ScmException;
27  import org.apache.maven.scm.ScmFileSet;
28  import org.apache.maven.scm.ScmVersion;
29  import org.apache.maven.scm.command.diff.AbstractDiffCommand;
30  import org.apache.maven.scm.command.diff.DiffScmResult;
31  import org.apache.maven.scm.provider.ScmProviderRepository;
32  import org.apache.maven.scm.provider.git.command.GitCommand;
33  import org.apache.maven.scm.provider.git.command.diff.GitDiffConsumer;
34  import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
35  import org.eclipse.jgit.api.Git;
36  import org.eclipse.jgit.api.errors.GitAPIException;
37  import org.eclipse.jgit.lib.ObjectId;
38  import org.eclipse.jgit.lib.ObjectReader;
39  import org.eclipse.jgit.lib.Repository;
40  import org.eclipse.jgit.revwalk.RevWalk;
41  import org.eclipse.jgit.treewalk.AbstractTreeIterator;
42  import org.eclipse.jgit.treewalk.CanonicalTreeParser;
43  
44  /**
45   * @author Dominik Bartholdi (imod)
46   * @since 1.9
47   */
48  public class JGitDiffCommand extends AbstractDiffCommand implements GitCommand {
49  
50      @Override
51      protected DiffScmResult executeDiffCommand(
52              ScmProviderRepository repository, ScmFileSet fileSet, ScmVersion startRevision, ScmVersion endRevision)
53              throws ScmException {
54  
55          Git git = null;
56          try {
57              git = JGitUtils.openRepo(fileSet.getBasedir());
58              DiffScmResult diff = callDiff(git, startRevision, endRevision);
59              git.getRepository().close();
60              return diff;
61          } catch (Exception e) {
62              throw new ScmException("JGit diff failure!", e);
63          } finally {
64              JGitUtils.closeRepo(git);
65          }
66      }
67  
68      public DiffScmResult callDiff(Git git, ScmVersion startRevision, ScmVersion endRevision)
69              throws IOException, GitAPIException, ScmException {
70  
71          AbstractTreeIterator oldTree = null;
72          if (startRevision != null
73                  && StringUtils.isNotEmpty(startRevision.getName().trim())) {
74              String startRev = startRevision.getName().trim();
75              oldTree = getTreeIterator(git.getRepository(), startRev);
76          }
77  
78          AbstractTreeIterator newTree = null;
79          if (endRevision != null && StringUtils.isNotEmpty(endRevision.getName().trim())) {
80              String endRev = endRevision.getName().trim();
81              newTree = getTreeIterator(git.getRepository(), endRev);
82          }
83  
84          OutputStream out = new ByteArrayOutputStream();
85  
86          git.diff()
87                  .setOutputStream(out)
88                  .setOldTree(oldTree)
89                  .setNewTree(newTree)
90                  .setCached(false)
91                  .call();
92          git.diff()
93                  .setOutputStream(out)
94                  .setOldTree(oldTree)
95                  .setNewTree(newTree)
96                  .setCached(true)
97                  .call();
98  
99          out.flush();
100 
101         GitDiffConsumer consumer = new GitDiffConsumer(null);
102         String fullDiff = out.toString();
103         out.close();
104 
105         String[] lines = fullDiff.split("\n");
106         for (String aLine : lines) {
107             consumer.consumeLine(aLine);
108         }
109 
110         return new DiffScmResult(
111                 "JGit diff", consumer.getChangedFiles(), consumer.getDifferences(), consumer.getPatch());
112     }
113 
114     private AbstractTreeIterator getTreeIterator(Repository repo, String name) throws IOException {
115         final ObjectId id = repo.resolve(name);
116         if (id == null) {
117             throw new IllegalArgumentException(name);
118         }
119         final CanonicalTreeParser p = new CanonicalTreeParser();
120 
121         try (ObjectReader or = repo.newObjectReader();
122                 RevWalk revWalk = new RevWalk(repo)) {
123             p.reset(or, revWalk.parseTree(id));
124             return p;
125         }
126     }
127 }