/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.util; import java.io.StringReader; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.TimeZone; import com.thoughtworks.go.domain.materials.Modification; import com.thoughtworks.go.domain.materials.ModifiedAction; import static com.thoughtworks.go.util.ExceptionUtils.bomb; import com.thoughtworks.go.domain.materials.svn.SvnCommand; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; public class SvnLogXmlParser { public List<Modification> parse(String svnLogOutput, String path, SAXBuilder builder) { try { Document document = builder.build(new StringReader(svnLogOutput)); return parseDOMTree(document, path); } catch (Exception e) { throw bomb("Unable to parse svn log output: " + svnLogOutput, e); } } private List<Modification> parseDOMTree(Document document, String path) throws ParseException { List<Modification> modifications = new ArrayList<>(); Element rootElement = document.getRootElement(); List logEntries = rootElement.getChildren("logentry"); for (Iterator iterator = logEntries.iterator(); iterator.hasNext();) { Element logEntry = (Element) iterator.next(); Modification modification = parseLogEntry(logEntry, path); if (modification != null) { modifications.add(modification); } } return modifications; } private Modification parseLogEntry(Element logEntry, String path) throws ParseException { Element logEntryPaths = logEntry.getChild("paths"); if (logEntryPaths == null) { /* Path-based access control forbids us from learning * details of this log entry, so skip it. */ return null; } Date modifiedTime = convertDate(logEntry.getChildText("date")); String author = logEntry.getChildText("author"); String comment = logEntry.getChildText("msg"); String revision = logEntry.getAttributeValue("revision"); Modification modification = new Modification(author, comment, null, modifiedTime, revision); List paths = logEntryPaths.getChildren("path"); for (Iterator iterator = paths.iterator(); iterator.hasNext();) { Element node = (Element) iterator.next(); if (underPath(path, node.getText())) { ModifiedAction action = convertAction(node.getAttributeValue("action")); modification.createModifiedFile(node.getText(), null, action); } } return modification; } private boolean underPath(String path, String text) { return text.startsWith(path); } /** * Converts the specified SVN date string into a Date. * * @param date with format "yyyy-MM-dd'T'HH:mm:ss.SSS" + "...Z" * @return converted date * @throws java.text.ParseException if specified date doesn't match the expected format */ static Date convertDate(String date) throws ParseException { final int zIndex = date.indexOf('Z'); if (zIndex - 3 < 0) { throw new ParseException(date + " doesn't match the expected subversion date format", date.length()); } String withoutMicroSeconds = date.substring(0, zIndex - 3); return getOutDateFormatter().parse(withoutMicroSeconds); } public static DateFormat getOutDateFormatter() { DateFormat f = new SimpleDateFormat(SvnCommand.SVN_DATE_FORMAT_OUT); f.setTimeZone(TimeZone.getTimeZone("GMT")); return f; } private ModifiedAction convertAction(String action) { if (action.equals("A")) { return ModifiedAction.added; } if (action.equals("M")) { return ModifiedAction.modified; } if (action.equals("D")) { return ModifiedAction.deleted; } return ModifiedAction.unknown; } public HashMap<String, String> parseInfoToGetUUID(String output, String queryURL, SAXBuilder builder) { HashMap<String, String> uidToUrlMap = new HashMap<>(); try { Document document = builder.build(new StringReader(output)); Element root = document.getRootElement(); List<Element> entries = root.getChildren("entry"); for (Element entry : entries) { uidToUrlMap.put(queryURL, entry.getChild("repository").getChild("uuid").getValue()); } } catch (Exception e) { throw new RuntimeException(e); } return uidToUrlMap; } }