PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/main/java/com/atlassian/maven/plugins/jgitflow/rewrite/MavenProjectRewriter.java

https://bitbucket.org/ronsmits/maven-jgitflow-plugin
Java | 286 lines | 174 code | 40 blank | 72 comment | 16 complexity | 3bc6876add9bab8c8fe04f40101d1db1 MD5 | raw file
  1. package com.atlassian.maven.plugins.jgitflow.rewrite;
  2. import java.io.*;
  3. import java.util.Iterator;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6. import com.atlassian.maven.plugins.jgitflow.exception.ProjectRewriteException;
  7. import org.apache.maven.project.MavenProject;
  8. import org.apache.maven.shared.release.util.ReleaseUtil;
  9. import org.codehaus.plexus.util.IOUtil;
  10. import org.codehaus.plexus.util.WriterFactory;
  11. import org.jdom2.*;
  12. import org.jdom2.filter.ContentFilter;
  13. import org.jdom2.input.SAXBuilder;
  14. import org.jdom2.output.Format;
  15. import org.jdom2.output.XMLOutputter;
  16. /**
  17. * @since version
  18. */
  19. public class MavenProjectRewriter implements ProjectRewriter
  20. {
  21. private static final int POM_INDENTATION = 4;
  22. private static final String ls = System.getProperty("line.separator");
  23. @Override
  24. public void applyChanges(MavenProject project, ProjectChangeset changes) throws ProjectRewriteException
  25. {
  26. File pomFile = project.getFile();
  27. if(null == pomFile || !pomFile.exists() || !pomFile.canRead())
  28. {
  29. String pomPath = (null == pomFile) ? "null" : pomFile.getAbsolutePath();
  30. throw new ProjectRewriteException("pom file must be readable! " + pomPath);
  31. }
  32. //Document document = readPom(pomFile);
  33. DocumentDescriptor dd = readPom(pomFile);
  34. Document document = dd.getDocument();
  35. Element root = document.getRootElement();
  36. boolean pomWasModified = false;
  37. pomWasModified |= applyAllChanges(project, root, changes.getItems());
  38. if(pomWasModified)
  39. {
  40. writePom(dd,pomFile);
  41. }
  42. }
  43. private void writePom(DocumentDescriptor dd, File f) throws ProjectRewriteException
  44. {
  45. Writer writer = null;
  46. String intro = dd.getIntro();
  47. String outtro = dd.getOuttro();
  48. Document document = dd.getDocument();
  49. try
  50. {
  51. writer = WriterFactory.newXmlWriter(f);
  52. if ( intro != null )
  53. {
  54. writer.write( intro );
  55. }
  56. Format format = Format.getRawFormat();
  57. format.setLineSeparator( ls );
  58. XMLOutputter out = new XMLOutputter( format );
  59. out.output( document.getRootElement(), writer );
  60. if ( outtro != null )
  61. {
  62. writer.write( outtro );
  63. }
  64. }
  65. catch (IOException e)
  66. {
  67. throw new ProjectRewriteException("Error writing pom!", e);
  68. }
  69. finally
  70. {
  71. IOUtil.close( writer );
  72. }
  73. }
  74. /*
  75. private void writePom(Document doc, File f) throws ProjectRewriteException
  76. {
  77. FileOutputStream fos = null;
  78. try
  79. {
  80. fos = new FileOutputStream(f);
  81. Format format = Format.getRawFormat();
  82. XMLOutputter out = new XMLOutputter(format);
  83. out.output(doc,fos);
  84. }
  85. catch (IOException e)
  86. {
  87. throw new ProjectRewriteException("Error writing pom!", e);
  88. }
  89. finally
  90. {
  91. IOUtil.close(fos);
  92. }
  93. }
  94. */
  95. private boolean applyAllChanges(MavenProject project, Element root, Iterable<ProjectChange> items) throws ProjectRewriteException
  96. {
  97. boolean modified = false;
  98. for(ProjectChange change : items)
  99. {
  100. boolean result = change.applyChange(project,root);
  101. if(!modified)
  102. {
  103. modified = result;
  104. }
  105. }
  106. return modified;
  107. }
  108. private DocumentDescriptor readPom(File pomFile) throws ProjectRewriteException
  109. {
  110. String intro = null;
  111. String outtro = null;
  112. try
  113. {
  114. String content = ReleaseUtil.readXmlFile(pomFile, ls);
  115. // we need to eliminate any extra whitespace inside elements, as JDOM will nuke it
  116. content = content.replaceAll( "<([^!][^>]*?)\\s{2,}([^>]*?)>", "<$1 $2>" );
  117. content = content.replaceAll( "(\\s{2,}|[^\\s])/>", "$1 />" );
  118. SAXBuilder builder = new SAXBuilder();
  119. Document document = builder.build( new StringReader( content ) );
  120. // Normalize line endings to platform's style (XML processors like JDOM normalize line endings to "\n" as
  121. // per section 2.11 of the XML spec)
  122. normaliseLineEndings( document );
  123. // rewrite DOM as a string to find differences, since text outside the root element is not tracked
  124. StringWriter w = new StringWriter();
  125. Format format = Format.getRawFormat();
  126. format.setLineSeparator( ls );
  127. XMLOutputter out = new XMLOutputter( format );
  128. out.output( document.getRootElement(), w );
  129. int index = content.indexOf( w.toString() );
  130. if ( index >= 0 )
  131. {
  132. intro = content.substring( 0, index );
  133. outtro = content.substring( index + w.toString().length() );
  134. }
  135. else
  136. {
  137. /*
  138. * NOTE: Due to whitespace, attribute reordering or entity expansion the above indexOf test can easily
  139. * fail. So let's try harder. Maybe some day, when JDOM offers a StaxBuilder and this builder employes
  140. * XMLInputFactory2.P_REPORT_PROLOG_WHITESPACE, this whole mess can be avoided.
  141. */
  142. final String SPACE = "\\s++";
  143. final String XML = "<\\?(?:(?:[^\"'>]++)|(?:\"[^\"]*+\")|(?:'[^\']*+'))*+>";
  144. final String INTSUB = "\\[(?:(?:[^\"'\\]]++)|(?:\"[^\"]*+\")|(?:'[^\']*+'))*+\\]";
  145. final String DOCTYPE =
  146. "<!DOCTYPE(?:(?:[^\"'\\[>]++)|(?:\"[^\"]*+\")|(?:'[^\']*+')|(?:" + INTSUB + "))*+>";
  147. final String PI = XML;
  148. final String COMMENT = "<!--(?:[^-]|(?:-[^-]))*+-->";
  149. final String INTRO =
  150. "(?:(?:" + SPACE + ")|(?:" + XML + ")|(?:" + DOCTYPE + ")|(?:" + COMMENT + ")|(?:" + PI + "))*";
  151. final String OUTRO = "(?:(?:" + SPACE + ")|(?:" + COMMENT + ")|(?:" + PI + "))*";
  152. final String POM = "(?s)(" + INTRO + ")(.*?)(" + OUTRO + ")";
  153. Matcher matcher = Pattern.compile(POM).matcher( content );
  154. if ( matcher.matches() )
  155. {
  156. intro = matcher.group( 1 );
  157. outtro = matcher.group( matcher.groupCount() );
  158. }
  159. }
  160. return new DocumentDescriptor(document,intro,outtro);
  161. }
  162. catch (IOException e)
  163. {
  164. throw new ProjectRewriteException("unable to read pom!", e);
  165. }
  166. catch (JDOMException e)
  167. {
  168. throw new ProjectRewriteException("unable to read pom!", e);
  169. }
  170. }
  171. private void normaliseLineEndings( Document document )
  172. {
  173. for ( Iterator<?> i = document.getDescendants( new ContentFilter( ContentFilter.COMMENT ) ); i.hasNext(); )
  174. {
  175. Comment c = (Comment) i.next();
  176. c.setText( ReleaseUtil.normalizeLineEndings( c.getText(), ls ) );
  177. }
  178. for ( Iterator<?> i = document.getDescendants( new ContentFilter( ContentFilter.CDATA ) ); i.hasNext(); )
  179. {
  180. CDATA c = (CDATA) i.next();
  181. c.setText( ReleaseUtil.normalizeLineEndings( c.getText(), ls ) );
  182. }
  183. }
  184. /*
  185. private Document readPom(File pomFile) throws ProjectRewriteException
  186. {
  187. FileInputStream fis = null;
  188. try
  189. {
  190. fis = new FileInputStream(pomFile);
  191. final StAXStreamBuilder builder = new StAXStreamBuilder();
  192. XMLInputFactory inputFactory = XMLInputFactory.newInstance();
  193. XMLStreamReader streamReader = inputFactory.createXMLStreamReader(fis);
  194. return builder.build(streamReader);
  195. }
  196. catch (XMLStreamException e)
  197. {
  198. throw new ProjectRewriteException("unable to read pom!", e);
  199. }
  200. catch (JDOMException e)
  201. {
  202. throw new ProjectRewriteException("unable to read pom!", e);
  203. }
  204. catch (IOException e)
  205. {
  206. throw new ProjectRewriteException("unable to read pom!", e);
  207. }
  208. finally
  209. {
  210. if(null != fis)
  211. {
  212. IOUtil.close(fis);
  213. }
  214. }
  215. }
  216. */
  217. private class DocumentDescriptor
  218. {
  219. private final Document document;
  220. private final String intro;
  221. private final String outtro;
  222. private DocumentDescriptor(Document document, String intro, String outtro)
  223. {
  224. this.document = document;
  225. this.intro = intro;
  226. this.outtro = outtro;
  227. }
  228. public Document getDocument()
  229. {
  230. return document;
  231. }
  232. public String getIntro()
  233. {
  234. return intro;
  235. }
  236. public String getOuttro()
  237. {
  238. return outtro;
  239. }
  240. }
  241. }