PageRenderTime 27ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/opup/src/old/java/com/atlassian/labs/opup/PomScanner.java

https://bitbucket.org/jwalton/opup
Java | 314 lines | 248 code | 60 blank | 6 comment | 38 complexity | 261dac0d3bed0ecb72d2644dfdc5ecd0 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. package com.atlassian.labs.opup;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.util.ArrayList;
  6. import java.util.Collection;
  7. import java.util.HashMap;
  8. import java.util.HashSet;
  9. import java.util.Iterator;
  10. import java.util.Map;
  11. import java.util.Set;
  12. import java.util.regex.Matcher;
  13. import java.util.regex.Pattern;
  14. import javax.xml.parsers.DocumentBuilder;
  15. import javax.xml.parsers.DocumentBuilderFactory;
  16. import javax.xml.parsers.ParserConfigurationException;
  17. import javax.xml.xpath.XPath;
  18. import javax.xml.xpath.XPathConstants;
  19. import javax.xml.xpath.XPathExpression;
  20. import javax.xml.xpath.XPathExpressionException;
  21. import javax.xml.xpath.XPathFactory;
  22. import org.apache.maven.artifact.versioning.ArtifactVersion;
  23. import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
  24. import org.w3c.dom.Document;
  25. import org.w3c.dom.Element;
  26. import org.w3c.dom.NodeList;
  27. import org.xml.sax.SAXException;
  28. public class PomScanner
  29. {
  30. public static Iterable<File> pomFiles(File base)
  31. {
  32. ArrayList<File> poms = new ArrayList<File>();
  33. recurse(poms, base);
  34. return poms;
  35. }
  36. private static void recurse(Collection<? super File> poms, File dir)
  37. {
  38. File p = new File(dir, "pom.xml");
  39. if (p.isFile())
  40. {
  41. poms.add(p);
  42. for (File f : dir.listFiles())
  43. {
  44. if (f.isDirectory())
  45. {
  46. recurse(poms, f);
  47. }
  48. }
  49. }
  50. }
  51. private final Set<String> defined = new HashSet<String>();
  52. private final DocumentBuilder docBuilder;
  53. private final XPath xpath;
  54. private final Map<String, Collection<String>> versions = new HashMap<String, Collection<String>>();
  55. private final Map<String, Collection<String>> properties = new HashMap<String, Collection<String>>();
  56. private final Set<String> requirements = new HashSet<String>();
  57. public PomScanner() throws ParserConfigurationException
  58. {
  59. docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
  60. xpath = XPathFactory.newInstance().newXPath();
  61. }
  62. private static <K, V> void add(Map<K, Collection<V>> m, K k, V v)
  63. {
  64. Collection<V> c = m.get(k);
  65. if (c == null)
  66. {
  67. c = new HashSet<V>();
  68. m.put(k, c);
  69. }
  70. c.add(v);
  71. }
  72. void addVersion(String groupAndArtifact, String version)
  73. {
  74. add(versions, groupAndArtifact, version);
  75. }
  76. void addProperty(String name, String value)
  77. {
  78. add(properties, name, value);
  79. }
  80. public void process(InputStream in) throws SAXException, IOException, XPathExpressionException
  81. {
  82. Document d = docBuilder.parse(in);
  83. /* This pom's artifact */
  84. String pomGroupId = (String) xpath.evaluate("project/groupId", d, XPathConstants.STRING);
  85. String pomArtifactId = (String) xpath.evaluate("project/artifactId", d, XPathConstants.STRING);
  86. if (pomGroupId.isEmpty())
  87. {
  88. pomGroupId = (String) xpath.evaluate("project/parent/groupId", d, XPathConstants.STRING);
  89. }
  90. String pomCoords = pomGroupId + ":" + pomArtifactId;
  91. defined.add(pomCoords);
  92. /* Any dependency versions defined */
  93. XPathExpression expr = xpath.compile("//dependency[groupId and artifactId]");
  94. NodeList nl = (NodeList) expr.evaluate(d, XPathConstants.NODESET);
  95. for (int i = 0; i < nl.getLength(); i++)
  96. {
  97. Element e = (Element) nl.item(i);
  98. String groupId = (String) xpath.evaluate("groupId", e, XPathConstants.STRING);
  99. String artifactId = (String) xpath.evaluate("artifactId", e, XPathConstants.STRING);
  100. String version = (String) xpath.evaluate("version", e, XPathConstants.STRING);
  101. String type = (String) xpath.evaluate("type", e, XPathConstants.STRING);
  102. String scope = (String) xpath.evaluate("scope", e, XPathConstants.STRING);
  103. String coords = groupId + ":" + artifactId;
  104. if (!type.isEmpty() && !type.equals("jar"))
  105. {
  106. coords += ":" + type;
  107. }
  108. // Don't want to upgrade provided dependencies
  109. if (scope == null || !scope.equals("provided"))
  110. {
  111. requirements.add(coords);
  112. }
  113. if (!version.isEmpty())
  114. {
  115. addVersion(groupId + ":" + artifactId, version);
  116. }
  117. }
  118. /* Properties */
  119. nl = (NodeList) xpath.evaluate("project/properties/*", d, XPathConstants.NODESET);
  120. for (int i = 0; i < nl.getLength(); i++)
  121. {
  122. Element e = (Element) nl.item(i);
  123. addProperty(e.getTagName(), (String) xpath.evaluate(".", e, XPathConstants.STRING));
  124. }
  125. nl = (NodeList) xpath.evaluate("project/profiles/profile/properties/*", d, XPathConstants.NODESET);
  126. for (int i = 0; i < nl.getLength(); i++)
  127. {
  128. Element e = (Element) nl.item(i);
  129. addProperty(e.getTagName(), (String) xpath.evaluate(".", e, XPathConstants.STRING));
  130. }
  131. }
  132. public Collection<? extends String> getDefinedArtifacts()
  133. {
  134. return defined;
  135. }
  136. static String groupAndArtifact(String coords)
  137. {
  138. String s = coords;
  139. int sc = s.indexOf(':', s.indexOf(':') + 1);
  140. if (sc >= 0)
  141. {
  142. s = s.substring(0, sc);
  143. }
  144. return s;
  145. }
  146. private Collection<ArtifactVersion> toVersions(Collection<String> vs)
  147. {
  148. Collection<ArtifactVersion> artifactVersions = new ArrayList<ArtifactVersion>();
  149. for (String s : vs)
  150. {
  151. artifactVersions.add(new DefaultArtifactVersion(s));
  152. }
  153. return artifactVersions;
  154. }
  155. Map<String, ArtifactVersion> currentVersions = new HashMap<String, ArtifactVersion>();
  156. Map<String, ArtifactVersion> currentProperties = new HashMap<String, ArtifactVersion>();
  157. public Map<String, ArtifactVersion> getCurrentVersions()
  158. {
  159. return currentVersions;
  160. }
  161. public Map<String, ArtifactVersion> getCurrentProperties()
  162. {
  163. return currentProperties;
  164. }
  165. public void findCurrent(ReportTarget report)
  166. {
  167. Set<String> external = new HashSet<String>(requirements);
  168. /* We don't want anything we already have */
  169. Iterator<String> i = external.iterator();
  170. while (i.hasNext())
  171. {
  172. String s = groupAndArtifact(i.next());
  173. if (defined.contains(s))
  174. {
  175. i.remove();
  176. }
  177. }
  178. for (String s : external)
  179. {
  180. Collection<String> v = versions.get(groupAndArtifact(s));
  181. if (v.size() != 1)
  182. {
  183. report.multipleVersions(s, toVersions(v));
  184. }
  185. else if (v.iterator().next().startsWith("$"))
  186. {
  187. String expr = v.iterator().next();
  188. String propname = propNameFromExpression(expr);
  189. if (propname != null)
  190. {
  191. /* Don't try to upgrade internal dependencies */
  192. if (propname.equals("project.version"))
  193. {
  194. continue;
  195. }
  196. Collection<String> values = properties.get(propname);
  197. if (values == null)
  198. {
  199. throw new RuntimeException("No value for: " + propname);
  200. }
  201. else if (values.size() != 1)
  202. {
  203. report.multipleValues(propname, toVersions(values));
  204. }
  205. else
  206. {
  207. ArtifactVersion current = new DefaultArtifactVersion(values.iterator().next());
  208. currentVersions.put(s, current);
  209. currentProperties.put(propname, current);
  210. }
  211. }
  212. else
  213. {
  214. throw new RuntimeException("Bad expression: " + expr);
  215. }
  216. }
  217. else
  218. {
  219. currentVersions.put(s, new DefaultArtifactVersion(v.iterator().next()));
  220. }
  221. }
  222. }
  223. public String getPropertyForArtifactVersion(String artifact)
  224. {
  225. Collection<String> v = versions.get(groupAndArtifact(artifact));
  226. if (v.size() == 1 && v.iterator().next().startsWith("$"))
  227. {
  228. String expr = v.iterator().next();
  229. String prop = propNameFromExpression(expr);
  230. if (prop == null)
  231. {
  232. throw new RuntimeException("Bad expression: " + expr);
  233. }
  234. return prop;
  235. }
  236. else
  237. {
  238. return null;
  239. }
  240. }
  241. private static final Pattern SINGLE_PROPERTY_EXPRESSION = Pattern.compile("\\$\\{([-\\._a-zA-Z0-9]+)\\}");
  242. public String propNameFromExpression(String expr)
  243. {
  244. Matcher m = SINGLE_PROPERTY_EXPRESSION.matcher(expr);
  245. if (m.matches())
  246. {
  247. return m.group(1);
  248. }
  249. else
  250. {
  251. return null;
  252. }
  253. }
  254. }