/*
* Name: GenericCompiler
* Authors: Richard Rodger
*
* Copyright (c) 2004 Richard Rodger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
// package
package org.jostraca.process;
// import
import org.jostraca.Property;
import org.jostraca.Template;
import org.jostraca.UserText;
import org.jostraca.util.PropertySet;
import org.jostraca.util.Standard;
import org.jostraca.util.TextUtil;
import org.jostraca.util.BasicWayPoint;
import org.jostraca.util.WayPointRecorder;
import org.jostraca.util.ExecutableCommand;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.io.File;
/** Processing class for generic compilation using an external compiler.
*/
public class GenericCompiler extends TemplateHandlerSupport {
public GenericCompiler() {
// do nothing
}
protected void processImpl( Template pTemplate ) {
}
protected void completeImpl( List pTemplateList ) {
List tmlist = pTemplateList;
// sort each template into an equivalent compile operation
HashMap compileBag = new HashMap();
for( Iterator tmT = tmlist.iterator(); tmT.hasNext(); ) {
Template tm = (Template) tmT.next();
String bagname = resolveBagName( tm );
ArrayList bagtmlist = null;
if( !compileBag.containsKey( bagname ) ) {
bagtmlist = new ArrayList();
compileBag.put( bagname, bagtmlist );
}
else {
bagtmlist = (ArrayList) compileBag.get( bagname );
}
bagtmlist.add( tm );
}
for( Iterator bagT = compileBag.keySet().iterator(); bagT.hasNext(); ) {
String bagname = (String) bagT.next();
ArrayList bagtmlist = (ArrayList) compileBag.get( bagname );
if( 0 < bagtmlist.size() ) {
compileAsFirst( bagtmlist );
}
}
}
protected String resolveBagName( Template pTemplate ) {
Template tm = pTemplate;
PropertySet tmps = tm.getMergedPropertySet();
StringBuffer bagname = new StringBuffer();
bagname.append( " "+tmps.get( Property.main_ExternalCompiler ) );
bagname.append( " "+tmps.get( Property.main_ExternalCompilerOptions ) );
return bagname.toString();
}
// compile using props from first tm
protected void compileAsFirst( List pTemplateList ) {
List tmlist = pTemplateList;
Template firsttm = (Template) pTemplateList.get(0);
PropertySet tmps = firsttm.getMergedPropertySet();
boolean successful = false;
boolean compile = false;
StringBuffer sourceFilesB = new StringBuffer();
for( Iterator tmT = tmlist.iterator(); tmT.hasNext(); ) {
Template tm = (Template) tmT.next();
File executablePath = makeExecutablePath( tm );
tm.setCodeWriterExecutablePath( executablePath );
boolean compileRequired = compileRequired( tm );
if( compileRequired ) {
File cwF = tm.getCodeWriterPath();
sourceFilesB.append( " "+TextUtil.quoteSpaces( cwF.getPath() ) );
WayPointRecorder.add( BasicWayPoint.CompilingCodeWriter.make( cwF.getAbsolutePath() ) );
compile = true;
}
}
if( compile ) {
String sourceFiles = sourceFilesB.toString();
String compiler = tmps.get( Property.main_ExternalCompiler );
String compilerOpts = tmps.get( Property.main_ExternalCompilerOptions );
ExecutableCommand cmd = new ExecutableCommand( compiler, compilerOpts, sourceFiles );
String fullcmd = cmd.getFullCmd();
cmd.setUserMessageHandler( mUserMessageHandler );
cmd.setActivityDescription( UserText.get( UserText.TXT_compiling ) );
successful = cmd.execute();
if( !successful ) {
if( cmd.hasErrResult() ) {
throw ProcessException.CODE_compile_errors( cmd.getExecutedCmd() + Standard.NEWLINE
+ cmd.getOutResult() + Standard.NEWLINE
+ cmd.getErrResult() + Standard.NEWLINE
);
}
else if( cmd.wasNotFound() ) {
throw ProcessException.CODE_compiler_not_found( compiler );
}
else {
throw ProcessException.CODE_compile_failed( cmd.getExecutedCmd() + Standard.NEWLINE
+ cmd.getOutResult() + Standard.NEWLINE
+ cmd.getErrResult() + Standard.NEWLINE
);
}
}
}
}
protected boolean compileRequired( Template pTemplate ) {
try {
Template tm = pTemplate;
boolean compileRequired = true;
PropertySet tmps = tm.getMergedPropertySet();
StringBuffer reason = new StringBuffer();
File executablePath = pTemplate.getCodeWriterExecutablePath();
// definitely compile
if( tmps.isYes( Property.main_CompileCodeWriter ) ) {
compileRequired = true;
reason.append( "main.CompileCodeWriter="+tmps.get( Property.main_CompileCodeWriter ) );
}
// definitely do not compile
else if( tmps.isNo( Property.main_CompileCodeWriter ) ) {
compileRequired = false;
reason.append( "main.CompileCodeWriter="+tmps.get( Property.main_CompileCodeWriter ) );
}
// otherwise, compile only if needed
else if( tmps.isYes( Property.lang_HasExecutable ) ) {
// no executable => definitely compile
if( ! executablePath.exists() ) {
compileRequired = true;
reason.append( "executable not found: "+executablePath );
}
// code writer changed => definitely compile
else if( tm.getCodeWriterChanged() ) {
compileRequired = true;
reason.append( "CodeWriter changed" );
}
// no changes, so use the existing executable
else {
compileRequired = false;
reason.append( "no changes found" );
}
}
else {
compileRequired = false;
reason.append( "no executable" );
}
mUserMessageHandler.debug( "Compile Required:", ""+compileRequired+" ("+reason+")" );
return compileRequired;
}
catch( Exception e ) {
throw new ProcessException( e );
}
}
protected File makeExecutablePath( Template pTemplate ) {
File cwep = pTemplate.getCodeWriterExecutablePath();
return cwep;
}
}