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