/*
* P4Java - java integration with Perforce SCM
* Copyright (C) 2007-, Mike Wille, Tek42
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* You can contact the author at:
*
* Web: http://tek42.com
* Email: mike@tek42.com
* Mail: 755 W Big Beaver Road
* Suite 1110
* Troy, MI 48084
*/
package com.tek42.perforce.parse;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.tek42.perforce.PerforceException;
import com.tek42.perforce.model.Changelist;
/**
* Responsible for building and saving changelists.
*
* @author Mike Wille
*/
public class ChangelistBuilder implements Builder<Changelist> {
private final Logger logger = LoggerFactory.getLogger("perforce");
public String[] getBuildCmd(String p4exe, String id) {
return new String[] { p4exe, "describe", "-s", id };
}
/*
* (non-Javadoc)
*
* @see com.tek42.perforce.parse.Builder#build(java.lang.StringBuilder)
*/
public Changelist build(StringBuilder sb) throws PerforceException {
Changelist change = null;
StringTokenizer lines = new StringTokenizer(sb.toString(), "\t\n\r");
try {
while(lines.hasMoreElements()) {
String line = lines.nextToken();
logger.debug("Line: " + line);
if(line.startsWith("Change")) {
logger.debug("New changelist.");
change = new Changelist();
// Line looks like:
// Change XXXX by user@client on YYYY/MM/DD HH:MM:SS
StringTokenizer details = new StringTokenizer(line);
details.nextToken(); // client
change.setChangeNumber(new Integer(details.nextToken()));
details.nextToken(); // by
String user = details.nextToken();
change.setUser(user.substring(0, user.indexOf("@")));
change.setWorkspace(user.substring(user.indexOf("@") + 1));
details.nextToken(); // on
String date = details.nextToken();
String time = details.nextToken();
change.setDate(parseDate(date + " " + time));
// the lines immediately following is the description
StringBuilder desc = new StringBuilder();
line = lines.nextToken();
while(line != null && !line.startsWith("Affected files") && !line.startsWith("Jobs fixed")) {
logger.debug("Description Line: " + line);
desc.append(line + "\n");
line = lines.nextToken();
}
change.setDescription(desc.toString().trim());
}
if(line.startsWith("Jobs fixed")) {
logger.debug("Has jobs.");
List<Changelist.JobEntry> jobs = new ArrayList<Changelist.JobEntry>();
boolean getDesc = false;
Changelist.JobEntry job = new Changelist.JobEntry();
String description = null;
do {
line = lines.nextToken();
logger.debug("Job Line: " + line);
if(!getDesc) {
// Line looks like:
// EXT-84 on 2007/09/25 by mwille *closed*
StringTokenizer details = new StringTokenizer(line);
job = new Changelist.JobEntry();
job.setJob(details.nextToken());
details.nextToken(); // on
details.nextToken(); // date
String possibleUser = details.nextToken(); // by
String status = "";
if ("by".equals(possibleUser))
{
details.nextToken(); // user
status = details.nextToken(); // status
}
else
{
status = possibleUser;
}
job.setStatus(status);
description = "";
getDesc = true;
} else {
while(!line.startsWith("Affected files")) {
description += line;
if(!lines.hasMoreElements())
break;
description += "\n";
line = lines.nextToken();
}
job.setDescription(description.trim());
jobs.add(job);
getDesc = false;
}
} while(!line.startsWith("Affected files"));
change.setJobs(jobs);
}
if(line.startsWith("Affected files")) {
logger.debug("reading files...");
List<Changelist.FileEntry> files = new ArrayList<Changelist.FileEntry>();
while(lines.hasMoreElements()) {
String entry = lines.nextToken();
logger.debug("File Line: " + entry);
// if(!entry.startsWith("..."))
// break;
// line looks lie:
// ... //depot/path/to/file/file.ext#1 edit
int revStart = entry.indexOf("#");
if(revStart < 0)
continue;
String filename = entry.substring(4, revStart);
String rev = entry.substring(revStart + 1, entry.indexOf(" ", revStart));
String action = entry.substring(entry.indexOf(" ", revStart) + 1);
action = action.replace('/', '_');
Changelist.FileEntry file = new Changelist.FileEntry();
file.setFilename(filename);
file.setRevision(rev);
file.setAction(Changelist.FileEntry.Action.valueOf(action.toUpperCase(Locale.US)));
files.add(file);
}
change.setFiles(files);
}
}
} catch(Exception e) {
logger.error("Exception: " + e.getMessage());
throw new PerforceException("Failed to retrieve changelist.", e);
}
return change;
}
public String[] getSaveCmd(String p4exe, Changelist obj) {
return new String[] { p4exe, "change", "-i" };
}
public boolean requiresStandardInput() {
return true;
}
/*
* (non-Javadoc)
*
* @see com.tek42.perforce.parse.Builder#save(java.lang.Object)
*/
public void save(Changelist obj, Writer out) throws PerforceException {
throw new UnsupportedOperationException("This is not implemented.");
}
/**
* 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 parseDate(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();
}
}