implement new ChangesetViewer api

This commit is contained in:
Sebastian Sdorra
2011-04-16 17:24:59 +02:00
parent a93cded116
commit 00e3f79945
4 changed files with 288 additions and 212 deletions

View File

@@ -1,102 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository;
//~--- JDK imports ------------------------------------------------------------
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement(name = "changesets")
@XmlAccessorType(XmlAccessType.FIELD)
public class Changesets
{
/**
* Constructs ...
*
*/
public Changesets() {}
/**
* Constructs ...
*
*
* @param changesets
*/
public Changesets(List<Changeset> changesets)
{
this.changesets = changesets;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<Changeset> getChangesets()
{
return changesets;
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param changesets
*/
public void setChangesets(List<Changeset> changesets)
{
this.changesets = changesets;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@XmlElement(name = "changeset")
private List<Changeset> changesets;
}

View File

@@ -0,0 +1,259 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
/**
*
* @author Sebastian Sdorra
*/
public class HgChangesetParser
{
/** the logger for HgChangesetParser */
private static final Logger logger =
LoggerFactory.getLogger(HgChangesetParser.class);
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param in
*
* @return
*
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public List<Changeset> parse(InputSource in)
throws SAXException, IOException, ParserConfigurationException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return parse(builder.parse(in));
}
/**
* Method description
*
*
* @param document
*
* @return
*/
private List<Changeset> parse(Document document)
{
List<Changeset> changesetList = new ArrayList<Changeset>();
NodeList changesetNodeList = document.getElementsByTagName("changeset");
if (changesetNodeList != null)
{
for (int i = 0; i < changesetNodeList.getLength(); i++)
{
Node changesetNode = changesetNodeList.item(i);
Changeset changeset = parseChangesetNode(changesetNode);
if ((changeset != null) && changeset.isValid())
{
changesetList.add(changeset);
}
}
}
return changesetList;
}
/**
* Method description
*
*
* @param changeset
* @param node
*/
private void parseChangesetChildNode(Changeset changeset, Node node)
{
String name = node.getNodeName();
String value = node.getTextContent();
if (Util.isNotEmpty(value))
{
if ("id".equals(name))
{
changeset.setId(value);
}
else if ("author".equals(name))
{
changeset.setAuthor(value);
}
else if ("description".equals(name))
{
changeset.setDescription(value);
}
else if ("date".equals(name))
{
try
{
Date date = dateFormat.parse(value);
changeset.setDate(date.getTime());
}
catch (ParseException ex)
{
logger.warn("could not parse date", ex);
}
}
else if ("tags".equals(name))
{
changeset.setTags(getList(value));
}
else if ("branches".equals(name))
{
changeset.setBranches(getList(value));
}
else if ("files-added".equals(name))
{
getModifications(changeset).setAdded(getList(value));
}
else if ("files-mods".equals(name))
{
getModifications(changeset).setModified(getList(value));
}
else if ("files-dels".equals(name))
{
getModifications(changeset).setRemoved(getList(value));
}
}
}
/**
* Method description
*
*
* @param changesetNode
*
* @return
*/
private Changeset parseChangesetNode(Node changesetNode)
{
Changeset changeset = new Changeset();
NodeList childrenNodeList = changesetNode.getChildNodes();
if (childrenNodeList != null)
{
for (int i = 0; i < childrenNodeList.getLength(); i++)
{
Node child = childrenNodeList.item(i);
parseChangesetChildNode(changeset, child);
}
}
return changeset;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param value
*
* @return
*/
private List<String> getList(String value)
{
return Arrays.asList(value.split(" "));
}
/**
* Method description
*
*
* @param changeset
*
* @return
*/
private Modifications getModifications(Changeset changeset)
{
Modifications mods = changeset.getModifications();
if (mods == null)
{
mods = new Modifications();
changeset.setModifications(mods);
}
return mods;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private SimpleDateFormat dateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
}

View File

@@ -38,11 +38,13 @@ package sonia.scm.repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import sonia.scm.io.Command;
import sonia.scm.io.CommandResult;
import sonia.scm.io.SimpleCommand;
import sonia.scm.util.IOUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
@@ -50,16 +52,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Date;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;
/**
*
@@ -72,8 +67,20 @@ public class HgChangesetViewer implements ChangesetViewer
public static final String ID_TIP = "tip";
/** Field description */
//J-
public static final String TEMPLATE_CHANGESETS =
"<changeset><id>{rev}:{node|short}</id><author>{author|escape}</author><description>{desc|escape}</description><date>{date|isodatesec}</date></changeset>\n";
"<changeset>"
+ "<id>{rev}:{node|short}</id>"
+ "<author>{author|escape}</author>"
+ "<description>{desc|escape}</description>"
+ "<date>{date|isodatesec}</date>"
+ "<tags>{tags}</tags>"
+ "<branches>{branches}</branches>"
+ "<files-added>{file_adds}</files-added>"
+ "<files-mods>{file_mods}</files-mods>"
+ "<files-dels>{file_dels}</files-dels>"
+ "</changeset>\n";
//J+
/** Field description */
public static final String TEMPLATE_TOTAL = "{rev}";
@@ -82,10 +89,6 @@ public class HgChangesetViewer implements ChangesetViewer
private static final Logger logger =
LoggerFactory.getLogger(HgChangesetViewer.class);
/** Field description */
public static final Pattern REGEX_DATE =
Pattern.compile("<date>([^<]+)</date>");
//~--- constructors ---------------------------------------------------------
/**
@@ -138,36 +141,26 @@ public class HgChangesetViewer implements ChangesetViewer
if (result.isSuccessfull())
{
StringReader reader =
new StringReader(getFixedOutput(result.getOutput()));
Unmarshaller unmarshaller = handler.createChangesetUnmarshaller();
Changesets cs = (Changesets) unmarshaller.unmarshal(reader);
StringBuilder sb = new StringBuilder("<changesets>");
if ((cs != null) && Util.isNotEmpty(cs.getChangesets()))
{
changesets = new ChangesetPagingResult(total, cs.getChangesets());
}
else if (logger.isWarnEnabled())
{
logger.warn("could not find any changeset from {} to {}", start,
start + max);
}
}
else
{
logger.error("could not load changesets, hg return code: {}\n{}",
result.getReturnCode(), result.getOutput());
sb.append(result.getOutput()).append("</changesets>");
List<Changeset> changesetList = new HgChangesetParser().parse(
new InputSource(
new StringReader(sb.toString())));
changesets = new ChangesetPagingResult(total, changesetList);
}
}
catch (ParseException ex)
catch (ParserConfigurationException ex)
{
logger.error("could not parse changeset dates", ex);
logger.error("could not parse changesets", ex);
}
catch (IOException ex)
{
logger.error("could not load changesets", ex);
}
catch (JAXBException ex)
catch (SAXException ex)
{
logger.error("could not unmarshall changesets", ex);
}
@@ -179,44 +172,6 @@ public class HgChangesetViewer implements ChangesetViewer
return changesets;
}
/**
* Method description
*
*
* @param output
*
* @return
*
* @throws ParseException
*/
private String getFixedOutput(String output) throws ParseException
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
StringBuilder changesetLog = new StringBuilder("<changesets>");
StringTokenizer st = new StringTokenizer(output, "\n");
while (st.hasMoreElements())
{
String line = st.nextToken();
Matcher m = REGEX_DATE.matcher(line);
if (m.find())
{
String dateString = m.group(1);
Date date = sdf.parse(dateString);
line = m.replaceAll(
"<date>".concat(Long.toString(date.getTime())).concat("</date>"));
}
changesetLog.append(line);
}
changesetLog.append("</changesets>");
return changesetLog.toString();
}
/**
* Method description
*

View File

@@ -40,7 +40,6 @@ import com.google.inject.Singleton;
import org.slf4j.LoggerFactory;
import sonia.scm.ConfigurationException;
import sonia.scm.Type;
import sonia.scm.installer.HgInstaller;
import sonia.scm.installer.UnixHgInstaller;
@@ -62,8 +61,6 @@ import java.io.File;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
/**
*
@@ -101,16 +98,6 @@ public class HgRepositoryHandler
public HgRepositoryHandler(StoreFactory storeFactory, FileSystem fileSystem)
{
super(storeFactory, fileSystem);
try
{
changesetContext = JAXBContext.newInstance(Changesets.class);
}
catch (JAXBException ex)
{
throw new ConfigurationException(
"could not create JAXBContext for Changesets-Class", ex);
}
}
//~--- methods --------------------------------------------------------------
@@ -236,29 +223,6 @@ public class HgRepositoryHandler
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @return
*/
Unmarshaller createChangesetUnmarshaller()
{
Unmarshaller unmarshaller = null;
try
{
unmarshaller = changesetContext.createUnmarshaller();
}
catch (JAXBException ex)
{
throw new ConfigurationException(
"could not create Unmarshaller for Changeset-Class", ex);
}
return unmarshaller;
}
/**
* Method description
*