package hudson.plugins.perforce;
import com.tek42.perforce.model.Changelist;
import hudson.model.AbstractBuild;
import hudson.scm.ChangeLogParser;
import hudson.scm.ChangeLogSet;
import hudson.scm.ChangeLogSet.Entry;
import java.io.File;
import java.io.IOException;
import java.util.*;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class PerforceChangeLogParser extends ChangeLogParser {
/*
* @see hudson.scm.ChangeLogParser#parse(hudson.model.AbstractBuild, java.io.File)
*/
@Override
public ChangeLogSet<? extends Entry> parse(AbstractBuild build, File file) throws IOException, SAXException {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
ChangeLogHandler handler = new ChangeLogHandler(build);
parser.parse(file,handler);
return handler.getChangeLogSet();
} catch (Exception e) {
throw new SAXException("Could not parse perforce changelog: ",e);
}
}
public static class ChangeLogHandler extends DefaultHandler {
private Stack objects = new Stack();
private StringBuffer text = new StringBuffer();
private List<PerforceChangeLogEntry> changeLogEntries = null;
private PerforceChangeLogSet changeLogSet = null;
private AbstractBuild build = null;
public ChangeLogHandler(AbstractBuild build) {
this.build = build;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
text.append(ch, start, length);
}
@Override
public void endDocument() throws SAXException {
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("changelog")) {
//this is the root, so don't do anything
return;
}
if (objects.peek() instanceof Changelist) {
Changelist changelist = (Changelist) objects.peek();
if (qName.equalsIgnoreCase("changenumber")) {
changelist.setChangeNumber(new Integer(text.toString()));
return;
}
if (qName.equalsIgnoreCase("date")) {
changelist.setDate(stringDateToJavaDate(text.toString()));
return;
}
if (qName.equalsIgnoreCase("description")) {
changelist.setDescription(text.toString());
return;
}
if (qName.equalsIgnoreCase("user")) {
changelist.setUser(text.toString());
return;
}
if (qName.equalsIgnoreCase("workspace")) {
changelist.setWorkspace(text.toString());
return;
}
}
if (objects.peek() instanceof Changelist.JobEntry) {
Changelist.JobEntry job = (Changelist.JobEntry) objects.peek();
if (qName.equalsIgnoreCase("name")) {
job.setJob(text.toString());
return;
}
if (qName.equalsIgnoreCase("description")) {
job.setDescription(text.toString());
return;
}
if (qName.equalsIgnoreCase("status")) {
job.setStatus(text.toString());
return;
}
if (qName.equalsIgnoreCase("job")) {
objects.pop();
List joblist = (List) objects.peek();
joblist.add(job);
return;
}
}
if (objects.peek() instanceof Changelist.FileEntry) {
Changelist.FileEntry file = (Changelist.FileEntry) objects.peek();
if (qName.equalsIgnoreCase("name")) {
file.setFilename(text.toString());
return;
}
if (qName.equalsIgnoreCase("workspacePath")) {
file.setWorkspacePath(text.toString());
return;
}
if (qName.equalsIgnoreCase("action")) {
file.setAction(Changelist.FileEntry.Action.valueOf(text.toString()));
return;
}
if (qName.equalsIgnoreCase("rev")) {
file.setRevision(text.toString());
return;
}
if (qName.equalsIgnoreCase("changenumber")) {
file.setChangenumber(text.toString());
return;
}
if (qName.equalsIgnoreCase("file")) {
objects.pop();
List filelist = (List) objects.peek();
filelist.add(file);
return;
}
}
if (qName.equalsIgnoreCase("files")) {
ArrayList<Changelist.FileEntry> files = (ArrayList<Changelist.FileEntry>) objects.pop();
Changelist changelist = (Changelist) objects.peek();
changelist.setFiles(files);
return;
}
if (qName.equalsIgnoreCase("jobs")) {
ArrayList<Changelist.JobEntry> jobs = (ArrayList<Changelist.JobEntry>) objects.pop();
Changelist changelist = (Changelist) objects.peek();
changelist.setJobs(jobs);
return;
}
if (qName.equalsIgnoreCase("entry")) {
Changelist changelist = (Changelist) objects.pop();
PerforceChangeLogEntry entry = new PerforceChangeLogEntry(changeLogSet);
entry.setChange(changelist);
changeLogEntries.add(entry);
return;
}
}
@Override
public void startDocument() throws SAXException {
changeLogEntries = new ArrayList<PerforceChangeLogEntry>();
changeLogSet = new PerforceChangeLogSet(build, changeLogEntries);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
text.setLength(0);
if (qName.equalsIgnoreCase("changelog")) {
//this is the root, so don't do anything
return;
}
if (qName.equalsIgnoreCase("entry")) {
objects.push(new Changelist());
return;
}
if (objects.peek() instanceof Changelist) {
if (qName.equalsIgnoreCase("files")) {
objects.push(new ArrayList<Changelist.FileEntry>());
return;
}
if (qName.equalsIgnoreCase("jobs")) {
objects.push(new ArrayList<Changelist.JobEntry>());
return;
}
}
if (qName.equalsIgnoreCase("job")) {
objects.push(new Changelist.JobEntry());
return;
}
if (qName.equalsIgnoreCase("file")) {
objects.push(new Changelist.FileEntry());
return;
}
}
public PerforceChangeLogSet getChangeLogSet() {
return changeLogSet;
}
}
/**
* This takes a java.util.Date and converts it to a string.
*
* @return A string representation of the date
*/
public static String javaDateToStringDate(java.util.Date newDate) {
if (newDate == null)
return "";
GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
cal.clear();
cal.setTime(newDate);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DAY_OF_MONTH);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int min = cal.get(Calendar.MINUTE);
int sec = cal.get(Calendar.SECOND);
String date = year + "-" + putZero(month) + "-" + putZero(day);
if (hour + min + sec > 0)
date += " " + putZero(hour) + ":" + putZero(min) + ":" + putZero(sec);
return date;
}
/**
* Returns a java.util.Date object set to the time specified in newDate. The
* format expected is the format of: YYYY-MM-DD HH:MM:SS
*
* @param newDate
* the string date to convert
* @return A java.util.Date based off of the string format.
*/
public static java.util.Date stringDateToJavaDate(String newDate) {
// when we have a null from the database, give it zeros first.
if (newDate == null || newDate.equals("")) {
return null;
}
String[] parts = newDate.split(" ");
String[] date = parts[0].split("-");
String[] time = null;
if (parts.length > 1) {
time = parts[1].split(":");
time[2] = time[2].replaceAll("\\.0", "");
} else {
time = "00:00:00".split(":");
}
GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
cal.clear();
cal.set(new Integer(date[0]).intValue(), (new Integer(date[1]).intValue() - 1),
new Integer(date[2]).intValue(), new Integer(time[0]).intValue(), new Integer(time[1]).intValue(),
new Integer(time[2]).intValue());
return cal.getTime();
}
public static String putZero(int i) {
if (i < 10) {
return "0" + i;
}
return i + "";
}
}