package fr.ens.biologie.genomique.eoulsan.util.r;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import com.google.common.base.Joiner;
import fr.ens.biologie.genomique.eoulsan.data.DataFile;
import fr.ens.biologie.genomique.eoulsan.data.DataFiles;
import fr.ens.biologie.genomique.eoulsan.util.ProcessUtils;
import fr.ens.biologie.genomique.eoulsan.util.process.DockerManager;
import fr.ens.biologie.genomique.eoulsan.util.process.SimpleProcess;
/**
* This class define a Docker RExecutor.
* @author Laurent Jourdren
* @since 2.0
*/
public class DockerRExecutor extends ProcessRExecutor {
public static final String REXECUTOR_NAME = "docker";
private final String dockerImage;
@Override
public String getName() {
return REXECUTOR_NAME;
}
@Override
protected void putFile(final DataFile inputFile, final String outputFilename)
throws IOException {
final DataFile outputFile =
new DataFile(getOutputDirectory(), outputFilename);
// Check if the input and output file are the same
if (isSameLocalPath(inputFile, outputFile)) {
return;
}
// If input file is not local file use the super implementation
if (!inputFile.isLocalFile()) {
super.putFile(inputFile, outputFilename);
return;
}
final File inFile = inputFile.toFile();
// Check if the file is in the output directory (or a subdir) or in the
// temporary directory (or a subdir)
if (isInSubDir(getOutputDirectory(), inFile)
|| isInSubDir(getTemporaryDirectory(), inFile)) {
// If not, copy files
if (outputFile.exists()) {
throw new IOException("The output file already exists: " + outputFile);
}
DataFiles.copy(inputFile, outputFile);
} else {
// Else use default putFile implementation
super.putFile(inputFile, outputFilename);
}
}
private static boolean isInSubDir(File a, File b) {
final File aAbs = a.getAbsoluteFile();
final File bAbs = b.getAbsoluteFile();
final URI aURI = aAbs.toURI();
final URI bURI = bAbs.toURI();
return !bURI.equals(aURI.relativize(bURI));
}
@Override
protected void executeRScript(final File rScriptFile, final boolean sweave,
final String sweaveOuput, final File workflowOutputDir, final String... scriptArguments)
throws IOException {
final SimpleProcess process =
DockerManager.getInstance().createImageInstance(this.dockerImage);
final List<String> commandLine =
createCommand(rScriptFile, sweave, sweaveOuput, scriptArguments);
final File stdoutFile = changeFileExtension(rScriptFile, ".out");
final int exitValue = process.execute(commandLine, getOutputDirectory(),
Collections.singletonMap(LANG_ENVIRONMENT_VARIABLE, DEFAULT_R_LANG),
getTemporaryDirectory(), stdoutFile, stdoutFile, true, workflowOutputDir);
ProcessUtils.throwExitCodeException(exitValue,
Joiner.on(' ').join(commandLine));
}
//
// Constructor
//
/**
* Constructor.
* @param outputDirectory the output directory
* @param temporaryDirectory the temporary directory
* @param dockerImage docker image to use
* @throws IOException if an error occurs while creating the object
*/
public DockerRExecutor(final File outputDirectory,
final File temporaryDirectory, final String dockerImage)
throws IOException {
super(outputDirectory, temporaryDirectory);
if (dockerImage == null) {
throw new NullPointerException("dockerImage argument cannot be null");
}
this.dockerImage = dockerImage;
}
}