All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.atlassian.maven.plugins.jgitflow.rewrite.MavenProjectRewriter Maven / Gradle / Ivy

There is a newer version: 1.0-alpha27
Show newest version
package com.atlassian.maven.plugins.jgitflow.rewrite;

import java.io.*;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.atlassian.maven.plugins.jgitflow.exception.ProjectRewriteException;

import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.release.util.ReleaseUtil;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.WriterFactory;
import org.jdom2.*;
import org.jdom2.filter.ContentFilter;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

/**
 * @since version
 */
public class MavenProjectRewriter implements ProjectRewriter
{
    private static final int POM_INDENTATION = 4;
    private static final String ls = System.getProperty("line.separator");
    
    @Override
    public void applyChanges(MavenProject project, ProjectChangeset changes) throws ProjectRewriteException
    {
        File pomFile = project.getFile();
        
        if(null == pomFile || !pomFile.exists() || !pomFile.canRead())
        {
            String pomPath = (null == pomFile) ? "null" : pomFile.getAbsolutePath();
            
            throw new ProjectRewriteException("pom file must be readable! " + pomPath);
        }
        
        //Document document = readPom(pomFile);
        DocumentDescriptor dd = readPom(pomFile);
        Document document = dd.getDocument();
        Element root = document.getRootElement();
        
        boolean pomWasModified = false;
        
        pomWasModified |= applyAllChanges(project, root, changes.getItems());
        
        if(pomWasModified)
        {
            writePom(dd,pomFile);
        }
        
    }

    private void writePom(DocumentDescriptor dd, File f) throws ProjectRewriteException
    {
        Writer writer = null;
        String intro = dd.getIntro();
        String outtro = dd.getOuttro();
        Document document = dd.getDocument();
        
        try
        {
            writer = WriterFactory.newXmlWriter(f);

            if ( intro != null )
            {
                writer.write( intro );
            }

            Format format = Format.getRawFormat();
            format.setLineSeparator( ls );
            XMLOutputter out = new XMLOutputter( format );
            out.output( document.getRootElement(), writer );

            if ( outtro != null )
            {
                writer.write( outtro );
            }
        }
        catch (IOException e)
        {
            throw new ProjectRewriteException("Error writing pom!", e);
        }
        finally
        {
            IOUtil.close( writer );
        }

    }
    
    /*
    private void writePom(Document doc, File f) throws ProjectRewriteException
    {
        FileOutputStream fos = null;
        
        try
        {
            fos = new FileOutputStream(f);

            Format format = Format.getRawFormat();
            XMLOutputter out = new XMLOutputter(format);
            
            out.output(doc,fos);
        }
        
        catch (IOException e)
        {
            throw new ProjectRewriteException("Error writing pom!", e);
        }
        finally
        {
            IOUtil.close(fos);
        }
    }
    */

    private boolean applyAllChanges(MavenProject project, Element root, Iterable items) throws ProjectRewriteException
    {
        boolean modified = false;
        
        for(ProjectChange change : items)
        {
            boolean result = change.applyChange(project,root);
            
            if(!modified)
            {
                modified = result;
            }
        }
        
        return modified;
    }

    private DocumentDescriptor readPom(File pomFile) throws ProjectRewriteException
    {
        String intro = null;
        String outtro = null;
        
        try
        {
            String content = ReleaseUtil.readXmlFile(pomFile, ls);
            // we need to eliminate any extra whitespace inside elements, as JDOM will nuke it
            content = content.replaceAll( "<([^!][^>]*?)\\s{2,}([^>]*?)>", "<$1 $2>" );
            content = content.replaceAll( "(\\s{2,}|[^\\s])/>", "$1 />" );

            SAXBuilder builder = new SAXBuilder();
            Document document = builder.build( new StringReader( content ) );

            // Normalize line endings to platform's style (XML processors like JDOM normalize line endings to "\n" as
            // per section 2.11 of the XML spec)
            normaliseLineEndings( document );

            // rewrite DOM as a string to find differences, since text outside the root element is not tracked
            StringWriter w = new StringWriter();
            Format format = Format.getRawFormat();
            format.setLineSeparator( ls );
            XMLOutputter out = new XMLOutputter( format );
            out.output( document.getRootElement(), w );

            int index = content.indexOf( w.toString() );
            if ( index >= 0 )
            {
                intro = content.substring( 0, index );
                outtro = content.substring( index + w.toString().length() );
            }
            else
            {
                /*
                 * NOTE: Due to whitespace, attribute reordering or entity expansion the above indexOf test can easily
                 * fail. So let's try harder. Maybe some day, when JDOM offers a StaxBuilder and this builder employes
                 * XMLInputFactory2.P_REPORT_PROLOG_WHITESPACE, this whole mess can be avoided.
                 */
                final String SPACE = "\\s++";
                final String XML = "<\\?(?:(?:[^\"'>]++)|(?:\"[^\"]*+\")|(?:'[^\']*+'))*+>";
                final String INTSUB = "\\[(?:(?:[^\"'\\]]++)|(?:\"[^\"]*+\")|(?:'[^\']*+'))*+\\]";
                final String DOCTYPE =
                        "]++)|(?:\"[^\"]*+\")|(?:'[^\']*+')|(?:" + INTSUB + "))*+>";
                final String PI = XML;
                final String COMMENT = "";

                final String INTRO =
                        "(?:(?:" + SPACE + ")|(?:" + XML + ")|(?:" + DOCTYPE + ")|(?:" + COMMENT + ")|(?:" + PI + "))*";
                final String OUTRO = "(?:(?:" + SPACE + ")|(?:" + COMMENT + ")|(?:" + PI + "))*";
                final String POM = "(?s)(" + INTRO + ")(.*?)(" + OUTRO + ")";

                Matcher matcher = Pattern.compile(POM).matcher( content );
                if ( matcher.matches() )
                {
                    intro = matcher.group( 1 );
                    outtro = matcher.group( matcher.groupCount() );
                }
            }
            
            return new DocumentDescriptor(document,intro,outtro);
        }
        catch (IOException e)
        {
            throw new ProjectRewriteException("unable to read pom!", e);
        }
        catch (JDOMException e)
        {
            throw new ProjectRewriteException("unable to read pom!", e);
        }

    }

    private void normaliseLineEndings( Document document )
    {
        for ( Iterator i = document.getDescendants( new ContentFilter( ContentFilter.COMMENT ) ); i.hasNext(); )
        {
            Comment c = (Comment) i.next();
            c.setText( ReleaseUtil.normalizeLineEndings( c.getText(), ls ) );
        }
        for ( Iterator i = document.getDescendants( new ContentFilter( ContentFilter.CDATA ) ); i.hasNext(); )
        {
            CDATA c = (CDATA) i.next();
            c.setText( ReleaseUtil.normalizeLineEndings( c.getText(), ls ) );
        }
    }
    
    /*
    private Document readPom(File pomFile) throws ProjectRewriteException
    {
        FileInputStream fis = null;
        try 
        {
            fis = new FileInputStream(pomFile);
            final StAXStreamBuilder builder = new StAXStreamBuilder();
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            XMLStreamReader streamReader = inputFactory.createXMLStreamReader(fis);
            
            return builder.build(streamReader);
        }
        catch (XMLStreamException e)
        {
            throw new ProjectRewriteException("unable to read pom!", e);
        }
        catch (JDOMException e)
        {
            throw new ProjectRewriteException("unable to read pom!", e);
        }
        catch (IOException e)
        {
            throw new ProjectRewriteException("unable to read pom!", e);
        }
        finally
        {
            if(null != fis)
            {
                IOUtil.close(fis);
            }
        }
    }
    */

    private class DocumentDescriptor 
    {
        private final Document document;
        private final String intro;
        private final String outtro;

        private DocumentDescriptor(Document document, String intro, String outtro)
        {
            this.document = document;
            this.intro = intro;
            this.outtro = outtro;
        }

        public Document getDocument()
        {
            return document;
        }

        public String getIntro()
        {
            return intro;
        }

        public String getOuttro()
        {
            return outtro;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy