/* Copyright (c) 2007, http://www.codeviation.org project
* This program is made available under the terms of the MIT License.
*/
package hudson.plugins.codeviation;
import hudson.Extension;
import hudson.FilePath;
import hudson.FilePath.FileCallable;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Descriptor.FormException;
import hudson.remoting.VirtualChannel;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapper.Environment;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.util.FormValidation;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.logging.Logger;
import net.sf.json.JSONObject;
import org.codeviation.model.PersistenceManager;
import org.codeviation.model.Repository;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
/**
*
* @author pzajac
*/
public class PAntWrapper extends BuildWrapper {
@Deprecated private transient StaplerRequest req;
public String startDate;
public String endDate;
public int daysStep;
public String antOpts = "";
/** reppsitoryName=CVSROOT
*/
public String repositoryMapping;
static SimpleDateFormat f1 = new SimpleDateFormat("yyyy/MM/dd HH:mm");
static SimpleDateFormat f2 = new SimpleDateFormat("yyyy/MM/dd");
static SimpleDateFormat f3 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
static Logger log = Logger.getLogger(PAntWrapper.class.getName());
@Extension
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public PAntWrapper() {
}
String[] getRepMapArray() {
if (repositoryMapping != null) {
String strings[] = repositoryMapping.split("=");
if (strings.length == 2) {
strings[0] = strings[0].trim();
strings[1] = strings[1].trim();
if (strings[0].length() > 0 && strings[1].length() > 0) {
return strings;
}
}
}
return null;
}
/** @return pant's repository for the project
*/
public Repository getRepository() {
System.setProperty(PersistenceManager.PANT_CACHE_FOLDER,PAntWrapper.DESCRIPTOR.getpantCacheFolder().getAbsolutePath());
PersistenceManager pm = PersistenceManager.getDefault();
String rn = getRepositoryName();
if (rn == null || pm == null) {
return null;
}
return pm.getRepository(rn);
}
private String getRepositoryName() {
String strs[] = getRepMapArray();
return (strs != null) ? strs[0] : null;
}
private String getRelCvsPath() {
String strs[] = getRepMapArray();
return (strs != null) ? strs[1] : null;
}
@Override
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException {
if (!checkDate(getStartDate())) {
throw new IOException("Codeviation: invalid Starting date format - " + getStartDate());
}
if (!checkDate(getEndDate())) {
throw new IOException("Codeviation: invalid Ending date format - " + getEndDate());
}
File pantCache = DESCRIPTOR.getpantCacheFolder();
if (pantCache == null) {
throw new IOException("Codeviation: Pant cache folder doesn't exists. Set up it hudson global settings.");
}
String pantLibs = DESCRIPTOR.getPantLibs();
if (pantLibs == null || pantLibs.length() == 0) {
throw new IOException("Codeviation: pant libs folder is empty or is invalid. Set up it hudson global settings.");
}
if (getRepMapArray() == null) {
throw new IOException("Codeviation: Repository mapping is not configured");
}
initRepository(build);
return new EnvironmentImpl(build);
}
private void initRepository(AbstractBuild<?,?> build) throws IOException {
FilePath path = build.getWorkspace();
final String relCvs = getRelCvsPath();
String absPath = null;
try {
absPath = path.act(new FileCallable<String>(){
public String invoke(File f, VirtualChannel channel) throws IOException {
File newFile = (".".equals(relCvs) ? f :new File(f,relCvs));
newFile.mkdirs();
if (!newFile.isDirectory()) {
throw new IOException ("CVS checkout path doesn't exist:" + newFile);
}
return newFile.getAbsolutePath();
}
});
} catch(InterruptedException ie) {
throw new IOException(ie.getMessage());
}
String repName = getRepositoryName();
// repository definition in repositories.lst
// XXX two lines should be rewritten in patched ant with one line name = folder
String twoLines = repName + "\n" + absPath + "\n";
File f = DESCRIPTOR.getpantCacheFolder();
File repositories = new File (f,"repositories.lst");
if (repositories.exists()) {
byte buff[] = new byte[(int)repositories.length()];
FileInputStream fis = new FileInputStream(repositories);
try {
fis.read(buff);
} finally {
fis.close();
}
String strBuff = new String(buff);
// XXX Windows separator :(
if (strBuff.indexOf(twoLines) != -1) {
return;
}
}
Writer fos = new FileWriter(repositories,true);
try {
fos.write(twoLines );
} finally {
fos.close();
}
}
public String getStartDate() {
return startDate;
}
public String getEndDate() {
return endDate;
}
public void setStartDate(String date) {
this.startDate = date;
}
public void setEndDate(String date) {
this.endDate = date;
}
public void setDaysStep(String steps) {
if (steps == null) {
daysStep = 0;
} else {
try {
daysStep = Integer.parseInt(steps);
} catch(NumberFormatException pe) {}
}
}
public static Date parseDate(String str) {
try {
return f1.parse(str);
} catch(ParseException pe) {
try {
return f2.parse(str);
} catch(ParseException pe2) {
try {
return f3.parse(str);
} catch(ParseException pe3) {}
}
}
return null;
}
private static boolean checkDate(String str) {
if (str != null && str.trim().length() > 0) {
return parseDate(str) != null;
}
return false;
}
public static class DescriptorImpl extends BuildWrapperDescriptor {
public File pantLibsFolder;
public File pantCacheFolder;
DescriptorImpl() {
super(PAntWrapper.class);
load();
}
public String getDisplayName() {
return "Codeviation metrics";
}
public File getpantCacheFolder() {
File ret = null;
if (pantLibsFolder != null && pantCacheFolder.isDirectory()) {
ret = pantCacheFolder;
}
return ret;
}
// @return classpath
public String getPantLibs() {
StringBuilder builder = new StringBuilder();
if (pantLibsFolder != null && pantLibsFolder.isDirectory()) {
for (File f :pantLibsFolder.listFiles()) {
String path = f.getAbsolutePath();
if (path.endsWith(".jar")) {
if (builder.length() > 0) {
builder.append(":");
}
builder.append(path);
}
}
}
return builder.toString();
}
@Override
public boolean isApplicable(AbstractProject<?,?> item) {
return true;
}
@Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
req.bindParameters(this,"codeviation.");
save();
return true;
}
@Override
public String getHelpFile() {
return "/plugin/codeviation/help-projectConfig.html";
}
// XXX this validator didn't work, maybe problem with Wrappers in hudson
// In wrapper class is warning don't use this experimental class :(
public FormValidation doCheckA(@QueryParameter String value, @QueryParameter String name) {
if ("startDate".equals(name) || "endDate".equals(name)) {
if (checkDate(value)) {
return FormValidation.ok();
} else {
return FormValidation.error("Invalid date format (yyy/mm/dd hh:MM)");
}
} else {
if (value != null) {
try {
Integer.parseInt(value);
} catch (NumberFormatException e) {
return FormValidation.error("Not number");
}
}
return FormValidation.ok();
}
}
@Override
public PAntWrapper newInstance(StaplerRequest req, JSONObject formData) throws FormException {
PAntWrapper wrapper = new PAntWrapper();
req.bindParameters(wrapper,"codeviation.");
// System.out.println("startDate: " + req.getParameter("codeviation.startDate"));
// wrapper.setStartDate(req.getParameter("codeviation.startDate"));
// wrapper.setEndDate(req.getParameter("codeviation.endDate"));
// wrapper.setDaysStep(req.getParameter("codeviation.daysStep"));
// save();
return wrapper;
}
}
class EnvironmentImpl extends Environment {
AbstractBuild<?,?> build;
EnvironmentImpl(AbstractBuild<?,?> build) {
this.build = build;
}
@Override
public void buildEnvVars(Map<String, String> env) {
StringBuilder allAntOpts = new StringBuilder();
allAntOpts.append("-Dpant.cache.folder=\"" + DESCRIPTOR.getpantCacheFolder().getAbsolutePath() + "\" ");
allAntOpts.append("-Dbuild.compiler=org.codeviation.javac.MeasuringJavac ");
String buildDate = getBuildDate();
log.info("build.Date = " + buildDate);
if (buildDate != null) {
allAntOpts.append("-Dpant.cvs.tag=\"" + buildDate +"\" ");
}
if (antOpts != null) {
String value = antOpts.replace('\n', ' ');
value = value.replace((char)0x0d,' ');
value = value.replaceAll("\\s"," ");
allAntOpts.append(value );
//ANT_OPTS="-Xmx512m -Dbuild.compiler=org.codeviation.javac.MeasuringJavac\
//-Dpant.cache.folder=/space/pant/pantcache \
//-Dpant.log.file=$WORKSPACE/pant.log\
//-Dscrambler2=I-implicitly-accept-any-and-all-license-terms-required-by-any-files-scrambled-using-org.netbeans.nbbuild.Scramble-by-using-this-option-and-will-not-release-this-key-to-anyone-except-Sun-employees-and-other-explicitly-authorized-parties\
//-Dnetbeans.no.pre.unscramble=true "
}
env.put("ANT_OPTS",allAntOpts.toString());
// classpath
env.put("CLASSPATH",DESCRIPTOR.getPantLibs());
//PANT_LIB=$HOME/pant
//export CLASSPATH=$CLASSPATH:$PANT_LIB/issuezillaquery.jar:\
//$PANT_LIB/org-netbeans-modules-java-source.jar:\
//$PANT_LIB/pant.jar:\
//$PANT_LIB/javac-api.jar:\
//$PANT_LIB/javac-impl.jar:\
//$PANT_LIB/mtj.jar:\
//$PANT_LIB/org-openide-util.jar
//./pantloop.pl
env.put("PANT_CVS_DATE",buildDate );
env.put("PANT_CVS_TAG", buildDate );
}
public String getBuildDate() {
Date buildDate = new Date();
Date startDate = parseDate(getStartDate());
Date endDate = parseDate(getEndDate());
if (startDate != null && endDate!= null && startDate.compareTo(endDate) < 0) {
buildDate = startDate;
}
return f1.format(buildDate);
}
@Override
public boolean tearDown(AbstractBuild build, BuildListener arg1) throws IOException {
Date date = getNextBuildDate();
if (date != null) {
setStartDate(f1.format(date));
build.getProject().save();
build.getProject().scheduleBuild(new CodeviationCause());
}
return true;
}
}
private Date getNextBuildDate() {
Date startDate = parseDate(getStartDate());
Date endDate = parseDate(getEndDate());
Date retDate = null;
if (startDate != null && endDate != null && daysStep > 0) {
// increase date + daysStep days
startDate.setTime(startDate.getTime() + daysStep*3600L*1000*24);
if (startDate.compareTo(endDate) < 0) {
retDate = startDate;
}
}
return retDate;
}
}