com.atlassian.maven.plugins.jgitflow.rewrite.MavenProjectRewriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jgitflow-maven-plugin Show documentation
Show all versions of jgitflow-maven-plugin Show documentation
A maven plugin to support doing git-flow releases
The 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.jgitflow.core.CoreEol;
import com.atlassian.jgitflow.core.exception.JGitFlowException;
import com.atlassian.maven.plugins.jgitflow.exception.ProjectRewriteException;
import com.atlassian.maven.plugins.jgitflow.provider.ContextProvider;
import com.atlassian.maven.plugins.jgitflow.provider.JGitFlowProvider;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.release.util.ReleaseUtil;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
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
*/
@Component(role = ProjectRewriter.class)
public class MavenProjectRewriter implements ProjectRewriter
{
private static final int POM_INDENTATION = 4;
@Requirement
private JGitFlowProvider jGitFlowProvider;
@Requirement
private ContextProvider contextProvider;
@Override
public void applyChanges(MavenProject project, ProjectChangeset changes) throws ProjectRewriteException
{
String eol = null;
try
{
String eolParam = contextProvider.getContext().getEol();
if(CoreEol.isValid(eolParam))
{
eol = CoreEol.fromString(eolParam).getEol();
}
else
{
eol = CoreEol.getConfigValue(jGitFlowProvider.gitFlow().git().getRepository().getConfig()).getEol();
}
}
catch (JGitFlowException e)
{
throw new ProjectRewriteException("Error determining proper EOL!", e);
}
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, eol);
Document document = dd.getDocument();
Element root = document.getRootElement();
boolean pomWasModified = false;
pomWasModified |= applyAllChanges(project, root, changes.getItems(), eol);
if (pomWasModified)
{
writePom(dd, pomFile, eol);
}
}
private void writePom(DocumentDescriptor dd, File f, String eol) 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(eol);
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 boolean applyAllChanges(MavenProject project, Element root, Iterable items, String eol) throws ProjectRewriteException
{
boolean modified = false;
for (ProjectChange change : items)
{
boolean result = change.applyChange(project, root, eol);
if (!modified)
{
modified = result;
}
}
return modified;
}
private DocumentDescriptor readPom(File pomFile, String eol) throws ProjectRewriteException
{
String intro = null;
String outtro = null;
try
{
String content = ReleaseUtil.readXmlFile(pomFile, eol);
// 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, eol);
// 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(eol);
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, String eol)
{
for (Iterator> i = document.getDescendants(new ContentFilter(ContentFilter.COMMENT)); i.hasNext(); )
{
Comment c = (Comment) i.next();
c.setText(ReleaseUtil.normalizeLineEndings(c.getText(), eol));
}
for (Iterator> i = document.getDescendants(new ContentFilter(ContentFilter.CDATA)); i.hasNext(); )
{
CDATA c = (CDATA) i.next();
c.setText(ReleaseUtil.normalizeLineEndings(c.getText(), eol));
}
}
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;
}
}
}