mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-03-06 12:20:56 +01:00
implement new ChangesetViewer api
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user