package se.chalmers.gdcn.taskbuilder;
import org.apache.commons.io.IOUtils;
import se.chalmers.gdcn.taskbuilder.communicationToClient.TaskListener;
import se.chalmers.gdcn.taskbuilder.fileManagement.PathManager;
import se.chalmers.gdcn.taskbuilder.utils.FormatString;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Class for tasks, compiling and executing Haskell code
*/
public class Task implements Runnable{
private static final String[] trustedPackages = {"base", "bytestring", "mtl", "random", "gdcn-trusted"};
private final String projectName;
private final String taskName;
private final String moduleName;
private final List<String> initDataPaths;
private final PathManager pathManager;
private final TaskListener listener;
/**
*
* @param projectName Name of local folder to work in
* @param taskName Name of the task
* @param moduleName Name of the Haskell module
* @param initDataFiles List of paths to respective resource files
* @param listener Listener on success or failure
*/
public Task(String projectName, String taskName, String moduleName, List<String> initDataFiles, TaskListener listener) {
this.projectName = projectName;
this.taskName = taskName;
this.moduleName = moduleName;
this.initDataPaths = new ArrayList<>(initDataFiles);
this.listener = listener;
pathManager = PathManager.worker(this.projectName);
}
private String compiledModule(){
return pathManager.taskBinaryDir() + moduleName;
}
/**
* Compiles task code
*/
public void compile(){
List<File> dirs = new ArrayList<>();
dirs.add(new File(pathManager.taskBinaryDir()));
dirs.add(new File(pathManager.projectTempDir()));
for(File dir : dirs){
if(!dir.exists()){
dir.mkdirs();
}
}
//TODO Manage trust in a non hardcoded way
String[] commandInit = {"ghc", "-o", compiledModule(),
"-DMODULE=" + moduleName, "-i" + pathManager.taskCodeDir(), pathManager.header(),
"-outputdir", pathManager.taskTempDir(taskName)};
List<String> command = new ArrayList<>();
command.addAll(Arrays.asList(commandInit));
for (String trustedPackage : trustedPackages) {
command.add("-trust");
command.add(trustedPackage);
}
HaskellCompiler haskellCompiler = new HaskellCompiler();
// For demo
System.out.println();
System.out.println("Compiling task...");
System.out.println();
try {
haskellCompiler.compile(command);
}
catch (InterruptedException | IOException | ExitFailureException e) {
e.printStackTrace();
listener.taskFailed(moduleName, e.getMessage());
} finally {
pathManager.deleteTaskTemp(taskName);
}
}
/**
* Executes a task
*/
public void execute(){
List<String> command = new ArrayList<>();
command.add(compiledModule());
final String resultFile = pathManager.getResultFilePath(taskName);
command.add(resultFile);
command.addAll(initDataPaths);
System.out.println("Running task...");
System.out.println();
Process proc = null;
try {
//proc = new ProcessBuilder(command).inheritIO().start();
proc = new ProcessBuilder(command).start();
if (proc.waitFor() != 0) {
StringWriter writer = new StringWriter();
IOUtils.copy(proc.getErrorStream(), writer, null);
throw new ExitFailureException(writer.toString());
}
else {
//TODO Possibly wrap pure result data in a class
StringWriter writer = new StringWriter();
IOUtils.copy(proc.getInputStream(), writer, null);
System.out.println("Result of task:");
System.out.println(FormatString.colour(writer.toString(), FormatString.Colour.GREEN));
System.out.println();
listener.taskFinished(taskName);
}
}
catch (Exception e) {
if (proc != null) {
proc.destroy();
}
e.printStackTrace();
listener.taskFailed(taskName, e.getMessage());
}
}
/**
* Compiles and executes a task
*/
@Override
public void run(){
String execFilePath = compiledModule();
File executable = new File(execFilePath);
try {
if (executable.isDirectory()) {
throw new IOException(execFilePath + " is a directory.");
}
if (!executable.exists()) {
compile();
}
execute();
} catch (Exception e) {
e.printStackTrace();
listener.taskFailed(taskName, e.getMessage());
}
}
}