001package org.apache.maven.scm.provider.git.jgit.command.diff;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.scm.ScmException;
023import org.apache.maven.scm.ScmFileSet;
024import org.apache.maven.scm.ScmVersion;
025import org.apache.maven.scm.command.diff.AbstractDiffCommand;
026import org.apache.maven.scm.command.diff.DiffScmResult;
027import org.apache.maven.scm.provider.ScmProviderRepository;
028import org.apache.maven.scm.provider.git.command.GitCommand;
029import org.apache.maven.scm.provider.git.command.diff.GitDiffConsumer;
030import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
031import org.codehaus.plexus.util.StringUtils;
032import org.eclipse.jgit.api.Git;
033import org.eclipse.jgit.api.errors.GitAPIException;
034import org.eclipse.jgit.lib.ObjectId;
035import org.eclipse.jgit.lib.ObjectReader;
036import org.eclipse.jgit.lib.Repository;
037import org.eclipse.jgit.revwalk.RevWalk;
038import org.eclipse.jgit.treewalk.AbstractTreeIterator;
039import org.eclipse.jgit.treewalk.CanonicalTreeParser;
040
041import java.io.ByteArrayOutputStream;
042import java.io.IOException;
043import java.io.OutputStream;
044
045/**
046 * @author Dominik Bartholdi (imod)
047 * @since 1.9
048 */
049public class JGitDiffCommand
050    extends AbstractDiffCommand
051    implements GitCommand
052{
053
054    @Override
055    protected DiffScmResult executeDiffCommand( ScmProviderRepository repository, ScmFileSet fileSet,
056                                                ScmVersion startRevision, ScmVersion endRevision )
057        throws ScmException
058    {
059
060        Git git = null;
061        try
062        {
063            git = Git.open( fileSet.getBasedir() );
064            DiffScmResult diff = callDiff( git, startRevision, endRevision );
065            git.getRepository().close();
066            return diff;
067        }
068        catch ( Exception e )
069        {
070            throw new ScmException( "JGit diff failure!", e );
071        }
072        finally
073        {
074            JGitUtils.closeRepo( git );
075        }
076    }
077
078    public DiffScmResult callDiff( Git git, ScmVersion startRevision, ScmVersion endRevision )
079        throws IOException, GitAPIException, ScmException
080    {
081
082        AbstractTreeIterator oldTree = null;
083        if ( startRevision != null && StringUtils.isNotEmpty( startRevision.getName().trim() ) )
084        {
085            String startRev = startRevision.getName().trim();
086            oldTree = getTreeIterator( git.getRepository(), startRev );
087        }
088
089        AbstractTreeIterator newTree = null;
090        if ( endRevision != null && StringUtils.isNotEmpty( endRevision.getName().trim() ) )
091        {
092            String endRev = endRevision.getName().trim();
093            newTree = getTreeIterator( git.getRepository(), endRev );
094        }
095
096        OutputStream out = new ByteArrayOutputStream();
097
098        git.diff().setOutputStream( out ).setOldTree( oldTree ).setNewTree( newTree ).setCached( false ).call();
099        git.diff().setOutputStream( out ).setOldTree( oldTree ).setNewTree( newTree ).setCached( true ).call();
100
101        out.flush();
102
103        GitDiffConsumer consumer = new GitDiffConsumer( getLogger(), null );
104        String fullDiff = out.toString();
105        out.close();
106
107        String[] lines = fullDiff.split( "\n" );
108        for ( String aLine : lines )
109        {
110            consumer.consumeLine( aLine );
111        }
112
113        return new DiffScmResult( "JGit diff", consumer.getChangedFiles(), consumer.getDifferences(),
114                                  consumer.getPatch() );
115    }
116
117    private AbstractTreeIterator getTreeIterator( Repository repo, String name )
118        throws IOException
119    {
120        final ObjectId id = repo.resolve( name );
121        if ( id == null )
122        {
123            throw new IllegalArgumentException( name );
124        }
125        final CanonicalTreeParser p = new CanonicalTreeParser();
126        final ObjectReader or = repo.newObjectReader();
127        try
128        {
129            p.reset( or, new RevWalk( repo ).parseTree( id ) );
130            return p;
131        }
132        finally
133        {
134            or.release();
135        }
136    }
137}